blob: 56cf7e96e3fadac6efb3c5c0bef1e972b7958f2f [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
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
19#include "codegen_x86.h"
20#include "dex/quick/mir_to_lir-inl.h"
21#include "mirror/array.h"
22#include "x86_lir.h"
23
24namespace art {
25
26/*
27 * Perform register memory operation.
28 */
29LIR* X86Mir2Lir::GenRegMemCheck(ConditionCode c_code,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070030 int reg1, int base, int offset, ThrowKind kind) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070031 LIR* tgt = RawLIR(0, kPseudoThrowTarget, kind,
32 current_dalvik_offset_, reg1, base, offset);
33 OpRegMem(kOpCmp, reg1, base, offset);
34 LIR* branch = OpCondBranch(c_code, tgt);
35 // Remember branch target - will process later
36 throw_launchpads_.Insert(tgt);
37 return branch;
38}
39
40/*
Mark Mendell343adb52013-12-18 06:02:17 -080041 * Perform a compare of memory to immediate value
42 */
43LIR* X86Mir2Lir::GenMemImmedCheck(ConditionCode c_code,
44 int base, int offset, int check_value, ThrowKind kind) {
45 LIR* tgt = RawLIR(0, kPseudoThrowTarget, kind,
46 current_dalvik_offset_, base, check_value, 0);
47 NewLIR3(IS_SIMM8(check_value) ? kX86Cmp32MI8 : kX86Cmp32MI, base, offset, check_value);
48 LIR* branch = OpCondBranch(c_code, tgt);
49 // Remember branch target - will process later
50 throw_launchpads_.Insert(tgt);
51 return branch;
52}
53
54/*
Brian Carlstrom7940e442013-07-12 13:46:57 -070055 * Compare two 64-bit values
56 * x = y return 0
57 * x < y return -1
58 * x > y return 1
59 */
60void X86Mir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070061 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070062 FlushAllRegs();
63 LockCallTemps(); // Prepare for explicit register usage
64 LoadValueDirectWideFixed(rl_src1, r0, r1);
65 LoadValueDirectWideFixed(rl_src2, r2, r3);
66 // Compute (r1:r0) = (r1:r0) - (r3:r2)
67 OpRegReg(kOpSub, r0, r2); // r0 = r0 - r2
68 OpRegReg(kOpSbc, r1, r3); // r1 = r1 - r3 - CF
69 NewLIR2(kX86Set8R, r2, kX86CondL); // r2 = (r1:r0) < (r3:r2) ? 1 : 0
70 NewLIR2(kX86Movzx8RR, r2, r2);
71 OpReg(kOpNeg, r2); // r2 = -r2
72 OpRegReg(kOpOr, r0, r1); // r0 = high | low - sets ZF
73 NewLIR2(kX86Set8R, r0, kX86CondNz); // r0 = (r1:r0) != (r3:r2) ? 1 : 0
74 NewLIR2(kX86Movzx8RR, r0, r0);
75 OpRegReg(kOpOr, r0, r2); // r0 = r0 | r2
76 RegLocation rl_result = LocCReturn();
77 StoreValue(rl_dest, rl_result);
78}
79
80X86ConditionCode X86ConditionEncoding(ConditionCode cond) {
81 switch (cond) {
82 case kCondEq: return kX86CondEq;
83 case kCondNe: return kX86CondNe;
84 case kCondCs: return kX86CondC;
85 case kCondCc: return kX86CondNc;
86 case kCondMi: return kX86CondS;
87 case kCondPl: return kX86CondNs;
88 case kCondVs: return kX86CondO;
89 case kCondVc: return kX86CondNo;
90 case kCondHi: return kX86CondA;
91 case kCondLs: return kX86CondBe;
92 case kCondGe: return kX86CondGe;
93 case kCondLt: return kX86CondL;
94 case kCondGt: return kX86CondG;
95 case kCondLe: return kX86CondLe;
96 case kCondAl:
97 case kCondNv: LOG(FATAL) << "Should not reach here";
98 }
99 return kX86CondO;
100}
101
102LIR* X86Mir2Lir::OpCmpBranch(ConditionCode cond, int src1, int src2,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700103 LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700104 NewLIR2(kX86Cmp32RR, src1, src2);
105 X86ConditionCode cc = X86ConditionEncoding(cond);
106 LIR* branch = NewLIR2(kX86Jcc8, 0 /* lir operand for Jcc offset */ ,
107 cc);
108 branch->target = target;
109 return branch;
110}
111
112LIR* X86Mir2Lir::OpCmpImmBranch(ConditionCode cond, int reg,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700113 int check_value, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700114 if ((check_value == 0) && (cond == kCondEq || cond == kCondNe)) {
115 // TODO: when check_value == 0 and reg is rCX, use the jcxz/nz opcode
116 NewLIR2(kX86Test32RR, reg, reg);
117 } else {
118 NewLIR2(IS_SIMM8(check_value) ? kX86Cmp32RI8 : kX86Cmp32RI, reg, check_value);
119 }
120 X86ConditionCode cc = X86ConditionEncoding(cond);
121 LIR* branch = NewLIR2(kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc);
122 branch->target = target;
123 return branch;
124}
125
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700126LIR* X86Mir2Lir::OpRegCopyNoInsert(int r_dest, int r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700127 if (X86_FPREG(r_dest) || X86_FPREG(r_src))
128 return OpFpRegCopy(r_dest, r_src);
129 LIR* res = RawLIR(current_dalvik_offset_, kX86Mov32RR,
130 r_dest, r_src);
131 if (r_dest == r_src) {
132 res->flags.is_nop = true;
133 }
134 return res;
135}
136
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700137LIR* X86Mir2Lir::OpRegCopy(int r_dest, int r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700138 LIR *res = OpRegCopyNoInsert(r_dest, r_src);
139 AppendLIR(res);
140 return res;
141}
142
143void X86Mir2Lir::OpRegCopyWide(int dest_lo, int dest_hi,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700144 int src_lo, int src_hi) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700145 bool dest_fp = X86_FPREG(dest_lo) && X86_FPREG(dest_hi);
146 bool src_fp = X86_FPREG(src_lo) && X86_FPREG(src_hi);
147 assert(X86_FPREG(src_lo) == X86_FPREG(src_hi));
148 assert(X86_FPREG(dest_lo) == X86_FPREG(dest_hi));
149 if (dest_fp) {
150 if (src_fp) {
151 OpRegCopy(S2d(dest_lo, dest_hi), S2d(src_lo, src_hi));
152 } else {
153 // TODO: Prevent this from happening in the code. The result is often
154 // unused or could have been loaded more easily from memory.
155 NewLIR2(kX86MovdxrRR, dest_lo, src_lo);
156 NewLIR2(kX86MovdxrRR, dest_hi, src_hi);
157 NewLIR2(kX86PsllqRI, dest_hi, 32);
158 NewLIR2(kX86OrpsRR, dest_lo, dest_hi);
159 }
160 } else {
161 if (src_fp) {
162 NewLIR2(kX86MovdrxRR, dest_lo, src_lo);
163 NewLIR2(kX86PsrlqRI, src_lo, 32);
164 NewLIR2(kX86MovdrxRR, dest_hi, src_lo);
165 } else {
166 // Handle overlap
167 if (src_hi == dest_lo) {
168 OpRegCopy(dest_hi, src_hi);
169 OpRegCopy(dest_lo, src_lo);
170 } else {
171 OpRegCopy(dest_lo, src_lo);
172 OpRegCopy(dest_hi, src_hi);
173 }
174 }
175 }
176}
177
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700178void X86Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700179 UNIMPLEMENTED(FATAL) << "Need codegen for GenSelect";
180}
181
182void X86Mir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
buzbee0d829482013-10-11 15:24:55 -0700183 LIR* taken = &block_label_list_[bb->taken];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700184 RegLocation rl_src1 = mir_graph_->GetSrcWide(mir, 0);
185 RegLocation rl_src2 = mir_graph_->GetSrcWide(mir, 2);
Mark Mendell412d4f82013-12-18 13:32:36 -0800186 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
187
188 if (rl_src1.is_const) {
189 std::swap(rl_src1, rl_src2);
190 ccode = FlipComparisonOrder(ccode);
191 }
192 if (rl_src2.is_const) {
193 // Do special compare/branch against simple const operand
194 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
195 GenFusedLongCmpImmBranch(bb, rl_src1, val, ccode);
196 return;
197 }
198
Brian Carlstrom7940e442013-07-12 13:46:57 -0700199 FlushAllRegs();
200 LockCallTemps(); // Prepare for explicit register usage
201 LoadValueDirectWideFixed(rl_src1, r0, r1);
202 LoadValueDirectWideFixed(rl_src2, r2, r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700203 // Swap operands and condition code to prevent use of zero flag.
204 if (ccode == kCondLe || ccode == kCondGt) {
205 // Compute (r3:r2) = (r3:r2) - (r1:r0)
206 OpRegReg(kOpSub, r2, r0); // r2 = r2 - r0
207 OpRegReg(kOpSbc, r3, r1); // r3 = r3 - r1 - CF
208 } else {
209 // Compute (r1:r0) = (r1:r0) - (r3:r2)
210 OpRegReg(kOpSub, r0, r2); // r0 = r0 - r2
211 OpRegReg(kOpSbc, r1, r3); // r1 = r1 - r3 - CF
212 }
213 switch (ccode) {
214 case kCondEq:
215 case kCondNe:
216 OpRegReg(kOpOr, r0, r1); // r0 = r0 | r1
217 break;
218 case kCondLe:
219 ccode = kCondGe;
220 break;
221 case kCondGt:
222 ccode = kCondLt;
223 break;
224 case kCondLt:
225 case kCondGe:
226 break;
227 default:
228 LOG(FATAL) << "Unexpected ccode: " << ccode;
229 }
230 OpCondBranch(ccode, taken);
231}
232
Mark Mendell412d4f82013-12-18 13:32:36 -0800233void X86Mir2Lir::GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1,
234 int64_t val, ConditionCode ccode) {
235 int32_t val_lo = Low32Bits(val);
236 int32_t val_hi = High32Bits(val);
237 LIR* taken = &block_label_list_[bb->taken];
238 LIR* not_taken = &block_label_list_[bb->fall_through];
239 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
240 int32_t low_reg = rl_src1.low_reg;
241 int32_t high_reg = rl_src1.high_reg;
242
243 if (val == 0 && (ccode == kCondEq || ccode == kCondNe)) {
244 int t_reg = AllocTemp();
245 OpRegRegReg(kOpOr, t_reg, low_reg, high_reg);
246 FreeTemp(t_reg);
247 OpCondBranch(ccode, taken);
248 return;
249 }
250
251 OpRegImm(kOpCmp, high_reg, val_hi);
252 switch (ccode) {
253 case kCondEq:
254 case kCondNe:
255 OpCondBranch(kCondNe, (ccode == kCondEq) ? not_taken : taken);
256 break;
257 case kCondLt:
258 OpCondBranch(kCondLt, taken);
259 OpCondBranch(kCondGt, not_taken);
260 ccode = kCondUlt;
261 break;
262 case kCondLe:
263 OpCondBranch(kCondLt, taken);
264 OpCondBranch(kCondGt, not_taken);
265 ccode = kCondLs;
266 break;
267 case kCondGt:
268 OpCondBranch(kCondGt, taken);
269 OpCondBranch(kCondLt, not_taken);
270 ccode = kCondHi;
271 break;
272 case kCondGe:
273 OpCondBranch(kCondGt, taken);
274 OpCondBranch(kCondLt, not_taken);
275 ccode = kCondUge;
276 break;
277 default:
278 LOG(FATAL) << "Unexpected ccode: " << ccode;
279 }
280 OpCmpImmBranch(ccode, low_reg, val_lo, taken);
281}
282
Brian Carlstrom7940e442013-07-12 13:46:57 -0700283RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, int reg_lo,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700284 int lit, bool is_div) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700285 LOG(FATAL) << "Unexpected use of GenDivRemLit for x86";
286 return rl_dest;
287}
288
289RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, int reg_lo,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700290 int reg_hi, bool is_div) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700291 LOG(FATAL) << "Unexpected use of GenDivRem for x86";
292 return rl_dest;
293}
294
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700295bool X86Mir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700296 DCHECK_EQ(cu_->instruction_set, kX86);
297 RegLocation rl_src1 = info->args[0];
298 RegLocation rl_src2 = info->args[1];
299 rl_src1 = LoadValue(rl_src1, kCoreReg);
300 rl_src2 = LoadValue(rl_src2, kCoreReg);
301 RegLocation rl_dest = InlineTarget(info);
302 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
303 OpRegReg(kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
304 DCHECK_EQ(cu_->instruction_set, kX86);
305 LIR* branch = NewLIR2(kX86Jcc8, 0, is_min ? kX86CondG : kX86CondL);
306 OpRegReg(kOpMov, rl_result.low_reg, rl_src1.low_reg);
307 LIR* branch2 = NewLIR1(kX86Jmp8, 0);
308 branch->target = NewLIR0(kPseudoTargetLabel);
309 OpRegReg(kOpMov, rl_result.low_reg, rl_src2.low_reg);
310 branch2->target = NewLIR0(kPseudoTargetLabel);
311 StoreValue(rl_dest, rl_result);
312 return true;
313}
314
Vladimir Markoe508a202013-11-04 15:24:22 +0000315bool X86Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
316 RegLocation rl_src_address = info->args[0]; // long address
317 rl_src_address.wide = 0; // ignore high half in info->args[1]
318 RegLocation rl_dest = InlineTarget(info);
319 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
320 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
321 if (size == kLong) {
322 // Unaligned access is allowed on x86.
323 LoadBaseDispWide(rl_address.low_reg, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
324 StoreValueWide(rl_dest, rl_result);
325 } else {
326 DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord);
327 // Unaligned access is allowed on x86.
328 LoadBaseDisp(rl_address.low_reg, 0, rl_result.low_reg, size, INVALID_SREG);
329 StoreValue(rl_dest, rl_result);
330 }
331 return true;
332}
333
334bool X86Mir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
335 RegLocation rl_src_address = info->args[0]; // long address
336 rl_src_address.wide = 0; // ignore high half in info->args[1]
337 RegLocation rl_src_value = info->args[2]; // [size] value
338 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
339 if (size == kLong) {
340 // Unaligned access is allowed on x86.
341 RegLocation rl_value = LoadValueWide(rl_src_value, kCoreReg);
342 StoreBaseDispWide(rl_address.low_reg, 0, rl_value.low_reg, rl_value.high_reg);
343 } else {
344 DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord);
345 // Unaligned access is allowed on x86.
346 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
347 StoreBaseDisp(rl_address.low_reg, 0, rl_value.low_reg, size);
348 }
349 return true;
350}
351
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700352void X86Mir2Lir::OpLea(int rBase, int reg1, int reg2, int scale, int offset) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700353 NewLIR5(kX86Lea32RA, rBase, reg1, reg2, scale, offset);
354}
355
Ian Rogers468532e2013-08-05 10:56:33 -0700356void X86Mir2Lir::OpTlsCmp(ThreadOffset offset, int val) {
357 NewLIR2(kX86Cmp16TI8, offset.Int32Value(), val);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700358}
359
Vladimir Marko1c282e22013-11-21 14:49:47 +0000360bool X86Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
Vladimir Markoc29bb612013-11-27 16:47:25 +0000361 DCHECK_EQ(cu_->instruction_set, kX86);
362 // Unused - RegLocation rl_src_unsafe = info->args[0];
363 RegLocation rl_src_obj = info->args[1]; // Object - known non-null
364 RegLocation rl_src_offset = info->args[2]; // long low
365 rl_src_offset.wide = 0; // ignore high half in info->args[3]
366 RegLocation rl_src_expected = info->args[4]; // int, long or Object
367 // If is_long, high half is in info->args[5]
368 RegLocation rl_src_new_value = info->args[is_long ? 6 : 5]; // int, long or Object
369 // If is_long, high half is in info->args[7]
370
371 if (is_long) {
Vladimir Marko70b797d2013-12-03 15:25:24 +0000372 FlushAllRegs();
373 LockCallTemps();
Vladimir Markoa6fd8ba2013-12-13 10:53:49 +0000374 LoadValueDirectWideFixed(rl_src_expected, rAX, rDX);
375 LoadValueDirectWideFixed(rl_src_new_value, rBX, rCX);
Vladimir Marko70b797d2013-12-03 15:25:24 +0000376 NewLIR1(kX86Push32R, rDI);
377 MarkTemp(rDI);
378 LockTemp(rDI);
379 NewLIR1(kX86Push32R, rSI);
380 MarkTemp(rSI);
381 LockTemp(rSI);
Vladimir Markoa6fd8ba2013-12-13 10:53:49 +0000382 const int push_offset = 4 /* push edi */ + 4 /* push esi */;
383 LoadWordDisp(TargetReg(kSp), SRegOffset(rl_src_obj.s_reg_low) + push_offset, rDI);
384 LoadWordDisp(TargetReg(kSp), SRegOffset(rl_src_offset.s_reg_low) + push_offset, rSI);
Vladimir Marko70b797d2013-12-03 15:25:24 +0000385 NewLIR4(kX86LockCmpxchg8bA, rDI, rSI, 0, 0);
386 FreeTemp(rSI);
387 UnmarkTemp(rSI);
388 NewLIR1(kX86Pop32R, rSI);
389 FreeTemp(rDI);
390 UnmarkTemp(rDI);
391 NewLIR1(kX86Pop32R, rDI);
392 FreeCallTemps();
Vladimir Markoc29bb612013-11-27 16:47:25 +0000393 } else {
394 // EAX must hold expected for CMPXCHG. Neither rl_new_value, nor r_ptr may be in EAX.
395 FlushReg(r0);
396 LockTemp(r0);
397
398 // Release store semantics, get the barrier out of the way. TODO: revisit
399 GenMemBarrier(kStoreLoad);
400
401 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
402 RegLocation rl_new_value = LoadValue(rl_src_new_value, kCoreReg);
403
404 if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
405 // Mark card for object assuming new value is stored.
406 FreeTemp(r0); // Temporarily release EAX for MarkGCCard().
407 MarkGCCard(rl_new_value.low_reg, rl_object.low_reg);
408 LockTemp(r0);
409 }
410
411 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
412 LoadValueDirect(rl_src_expected, r0);
413 NewLIR5(kX86LockCmpxchgAR, rl_object.low_reg, rl_offset.low_reg, 0, 0, rl_new_value.low_reg);
414
415 FreeTemp(r0);
416 }
417
418 // Convert ZF to boolean
419 RegLocation rl_dest = InlineTarget(info); // boolean place for result
420 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
421 NewLIR2(kX86Set8R, rl_result.low_reg, kX86CondZ);
422 NewLIR2(kX86Movzx8RR, rl_result.low_reg, rl_result.low_reg);
423 StoreValue(rl_dest, rl_result);
424 return true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700425}
426
427LIR* X86Mir2Lir::OpPcRelLoad(int reg, LIR* target) {
428 LOG(FATAL) << "Unexpected use of OpPcRelLoad for x86";
429 return NULL;
430}
431
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700432LIR* X86Mir2Lir::OpVldm(int rBase, int count) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700433 LOG(FATAL) << "Unexpected use of OpVldm for x86";
434 return NULL;
435}
436
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700437LIR* X86Mir2Lir::OpVstm(int rBase, int count) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700438 LOG(FATAL) << "Unexpected use of OpVstm for x86";
439 return NULL;
440}
441
442void X86Mir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
443 RegLocation rl_result, int lit,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700444 int first_bit, int second_bit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700445 int t_reg = AllocTemp();
446 OpRegRegImm(kOpLsl, t_reg, rl_src.low_reg, second_bit - first_bit);
447 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, t_reg);
448 FreeTemp(t_reg);
449 if (first_bit != 0) {
450 OpRegRegImm(kOpLsl, rl_result.low_reg, rl_result.low_reg, first_bit);
451 }
452}
453
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700454void X86Mir2Lir::GenDivZeroCheck(int reg_lo, int reg_hi) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700455 int t_reg = AllocTemp();
456 OpRegRegReg(kOpOr, t_reg, reg_lo, reg_hi);
457 GenImmedCheck(kCondEq, t_reg, 0, kThrowDivZero);
458 FreeTemp(t_reg);
459}
460
461// Test suspend flag, return target of taken suspend branch
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700462LIR* X86Mir2Lir::OpTestSuspend(LIR* target) {
Ian Rogers468532e2013-08-05 10:56:33 -0700463 OpTlsCmp(Thread::ThreadFlagsOffset(), 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700464 return OpCondBranch((target == NULL) ? kCondNe : kCondEq, target);
465}
466
467// Decrement register and branch on condition
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700468LIR* X86Mir2Lir::OpDecAndBranch(ConditionCode c_code, int reg, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700469 OpRegImm(kOpSub, reg, 1);
470 return OpCmpImmBranch(c_code, reg, 0, target);
471}
472
buzbee11b63d12013-08-27 07:34:17 -0700473bool X86Mir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700474 RegLocation rl_src, RegLocation rl_dest, int lit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700475 LOG(FATAL) << "Unexpected use of smallLiteralDive in x86";
476 return false;
477}
478
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700479LIR* X86Mir2Lir::OpIT(ConditionCode cond, const char* guide) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700480 LOG(FATAL) << "Unexpected use of OpIT in x86";
481 return NULL;
482}
483
484void X86Mir2Lir::GenMulLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700485 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700486 LOG(FATAL) << "Unexpected use of GenX86Long for x86";
487}
488void X86Mir2Lir::GenAddLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700489 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700490 // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
491 // enough.
492 FlushAllRegs();
493 LockCallTemps(); // Prepare for explicit register usage
494 LoadValueDirectWideFixed(rl_src1, r0, r1);
495 LoadValueDirectWideFixed(rl_src2, r2, r3);
496 // Compute (r1:r0) = (r1:r0) + (r2:r3)
497 OpRegReg(kOpAdd, r0, r2); // r0 = r0 + r2
498 OpRegReg(kOpAdc, r1, r3); // r1 = r1 + r3 + CF
499 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
500 INVALID_SREG, INVALID_SREG};
501 StoreValueWide(rl_dest, rl_result);
502}
503
504void X86Mir2Lir::GenSubLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700505 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700506 // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
507 // enough.
508 FlushAllRegs();
509 LockCallTemps(); // Prepare for explicit register usage
510 LoadValueDirectWideFixed(rl_src1, r0, r1);
511 LoadValueDirectWideFixed(rl_src2, r2, r3);
512 // Compute (r1:r0) = (r1:r0) + (r2:r3)
513 OpRegReg(kOpSub, r0, r2); // r0 = r0 - r2
514 OpRegReg(kOpSbc, r1, r3); // r1 = r1 - r3 - CF
515 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
516 INVALID_SREG, INVALID_SREG};
517 StoreValueWide(rl_dest, rl_result);
518}
519
520void X86Mir2Lir::GenAndLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700521 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700522 // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
523 // enough.
524 FlushAllRegs();
525 LockCallTemps(); // Prepare for explicit register usage
526 LoadValueDirectWideFixed(rl_src1, r0, r1);
527 LoadValueDirectWideFixed(rl_src2, r2, r3);
528 // Compute (r1:r0) = (r1:r0) & (r2:r3)
529 OpRegReg(kOpAnd, r0, r2); // r0 = r0 & r2
530 OpRegReg(kOpAnd, r1, r3); // r1 = r1 & r3
531 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
532 INVALID_SREG, INVALID_SREG};
533 StoreValueWide(rl_dest, rl_result);
534}
535
536void X86Mir2Lir::GenOrLong(RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700537 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700538 // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
539 // enough.
540 FlushAllRegs();
541 LockCallTemps(); // Prepare for explicit register usage
542 LoadValueDirectWideFixed(rl_src1, r0, r1);
543 LoadValueDirectWideFixed(rl_src2, r2, r3);
544 // Compute (r1:r0) = (r1:r0) | (r2:r3)
545 OpRegReg(kOpOr, r0, r2); // r0 = r0 | r2
546 OpRegReg(kOpOr, r1, r3); // r1 = r1 | r3
547 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
548 INVALID_SREG, INVALID_SREG};
549 StoreValueWide(rl_dest, rl_result);
550}
551
552void X86Mir2Lir::GenXorLong(RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700553 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700554 // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
555 // enough.
556 FlushAllRegs();
557 LockCallTemps(); // Prepare for explicit register usage
558 LoadValueDirectWideFixed(rl_src1, r0, r1);
559 LoadValueDirectWideFixed(rl_src2, r2, r3);
560 // Compute (r1:r0) = (r1:r0) ^ (r2:r3)
561 OpRegReg(kOpXor, r0, r2); // r0 = r0 ^ r2
562 OpRegReg(kOpXor, r1, r3); // r1 = r1 ^ r3
563 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
564 INVALID_SREG, INVALID_SREG};
565 StoreValueWide(rl_dest, rl_result);
566}
567
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700568void X86Mir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700569 FlushAllRegs();
570 LockCallTemps(); // Prepare for explicit register usage
571 LoadValueDirectWideFixed(rl_src, r0, r1);
572 // Compute (r1:r0) = -(r1:r0)
573 OpRegReg(kOpNeg, r0, r0); // r0 = -r0
574 OpRegImm(kOpAdc, r1, 0); // r1 = r1 + CF
575 OpRegReg(kOpNeg, r1, r1); // r1 = -r1
576 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
577 INVALID_SREG, INVALID_SREG};
578 StoreValueWide(rl_dest, rl_result);
579}
580
Ian Rogers468532e2013-08-05 10:56:33 -0700581void X86Mir2Lir::OpRegThreadMem(OpKind op, int r_dest, ThreadOffset thread_offset) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700582 X86OpCode opcode = kX86Bkpt;
583 switch (op) {
584 case kOpCmp: opcode = kX86Cmp32RT; break;
585 case kOpMov: opcode = kX86Mov32RT; break;
586 default:
587 LOG(FATAL) << "Bad opcode: " << op;
588 break;
589 }
Ian Rogers468532e2013-08-05 10:56:33 -0700590 NewLIR2(opcode, r_dest, thread_offset.Int32Value());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700591}
592
593/*
594 * Generate array load
595 */
596void X86Mir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
Ian Rogersa9a82542013-10-04 11:17:26 -0700597 RegLocation rl_index, RegLocation rl_dest, int scale) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700598 RegisterClass reg_class = oat_reg_class_by_size(size);
599 int len_offset = mirror::Array::LengthOffset().Int32Value();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700600 RegLocation rl_result;
601 rl_array = LoadValue(rl_array, kCoreReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700602
Mark Mendell343adb52013-12-18 06:02:17 -0800603 int data_offset;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700604 if (size == kLong || size == kDouble) {
605 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
606 } else {
607 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
608 }
609
Mark Mendell343adb52013-12-18 06:02:17 -0800610 bool constant_index = rl_index.is_const;
611 int32_t constant_index_value = 0;
612 if (!constant_index) {
613 rl_index = LoadValue(rl_index, kCoreReg);
614 } else {
615 constant_index_value = mir_graph_->ConstantValue(rl_index);
616 // If index is constant, just fold it into the data offset
617 data_offset += constant_index_value << scale;
618 // treat as non array below
619 rl_index.low_reg = INVALID_REG;
620 }
621
Brian Carlstrom7940e442013-07-12 13:46:57 -0700622 /* null object? */
623 GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags);
624
625 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
Mark Mendell343adb52013-12-18 06:02:17 -0800626 if (constant_index) {
627 GenMemImmedCheck(kCondLs, rl_array.low_reg, len_offset,
628 constant_index_value, kThrowConstantArrayBounds);
629 } else {
630 GenRegMemCheck(kCondUge, rl_index.low_reg, rl_array.low_reg,
631 len_offset, kThrowArrayBounds);
632 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700633 }
Mark Mendell343adb52013-12-18 06:02:17 -0800634 rl_result = EvalLoc(rl_dest, reg_class, true);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700635 if ((size == kLong) || (size == kDouble)) {
Mark Mendell343adb52013-12-18 06:02:17 -0800636 LoadBaseIndexedDisp(rl_array.low_reg, rl_index.low_reg, scale, data_offset, rl_result.low_reg,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700637 rl_result.high_reg, size, INVALID_SREG);
638 StoreValueWide(rl_dest, rl_result);
639 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700640 LoadBaseIndexedDisp(rl_array.low_reg, rl_index.low_reg, scale,
641 data_offset, rl_result.low_reg, INVALID_REG, size,
642 INVALID_SREG);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700643 StoreValue(rl_dest, rl_result);
644 }
645}
646
647/*
648 * Generate array store
649 *
650 */
651void X86Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
Ian Rogersa9a82542013-10-04 11:17:26 -0700652 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700653 RegisterClass reg_class = oat_reg_class_by_size(size);
654 int len_offset = mirror::Array::LengthOffset().Int32Value();
655 int data_offset;
656
657 if (size == kLong || size == kDouble) {
658 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
659 } else {
660 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
661 }
662
663 rl_array = LoadValue(rl_array, kCoreReg);
Mark Mendell343adb52013-12-18 06:02:17 -0800664 bool constant_index = rl_index.is_const;
665 int32_t constant_index_value = 0;
666 if (!constant_index) {
667 rl_index = LoadValue(rl_index, kCoreReg);
668 } else {
669 // If index is constant, just fold it into the data offset
670 constant_index_value = mir_graph_->ConstantValue(rl_index);
671 data_offset += constant_index_value << scale;
672 // treat as non array below
673 rl_index.low_reg = INVALID_REG;
674 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700675
676 /* null object? */
677 GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags);
678
679 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
Mark Mendell343adb52013-12-18 06:02:17 -0800680 if (constant_index) {
681 GenMemImmedCheck(kCondLs, rl_array.low_reg, len_offset,
682 constant_index_value, kThrowConstantArrayBounds);
683 } else {
684 GenRegMemCheck(kCondUge, rl_index.low_reg, rl_array.low_reg,
685 len_offset, kThrowArrayBounds);
686 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700687 }
688 if ((size == kLong) || (size == kDouble)) {
689 rl_src = LoadValueWide(rl_src, reg_class);
690 } else {
691 rl_src = LoadValue(rl_src, reg_class);
692 }
693 // If the src reg can't be byte accessed, move it to a temp first.
694 if ((size == kSignedByte || size == kUnsignedByte) && rl_src.low_reg >= 4) {
695 int temp = AllocTemp();
696 OpRegCopy(temp, rl_src.low_reg);
697 StoreBaseIndexedDisp(rl_array.low_reg, rl_index.low_reg, scale, data_offset, temp,
698 INVALID_REG, size, INVALID_SREG);
699 } else {
700 StoreBaseIndexedDisp(rl_array.low_reg, rl_index.low_reg, scale, data_offset, rl_src.low_reg,
701 rl_src.high_reg, size, INVALID_SREG);
702 }
Ian Rogersa9a82542013-10-04 11:17:26 -0700703 if (card_mark) {
Ian Rogers773aab12013-10-14 13:50:10 -0700704 // Free rl_index if its a temp. Ensures there are 2 free regs for card mark.
Mark Mendell343adb52013-12-18 06:02:17 -0800705 if (!constant_index) {
706 FreeTemp(rl_index.low_reg);
707 }
Ian Rogersa9a82542013-10-04 11:17:26 -0700708 MarkGCCard(rl_src.low_reg, rl_array.low_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700709 }
710}
711
712void X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700713 RegLocation rl_src1, RegLocation rl_shift) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700714 // Default implementation is just to ignore the constant case.
715 GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
716}
717
718void X86Mir2Lir::GenArithImmOpLong(Instruction::Code opcode,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700719 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700720 // Default - bail to non-const handler.
721 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
722}
723
724} // namespace art