blob: 0133a0afaf505e7aaf57a79c8002737a5e3baab9 [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/*
41 * Compare two 64-bit values
42 * x = y return 0
43 * x < y return -1
44 * x > y return 1
45 */
46void X86Mir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070047 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070048 FlushAllRegs();
49 LockCallTemps(); // Prepare for explicit register usage
50 LoadValueDirectWideFixed(rl_src1, r0, r1);
51 LoadValueDirectWideFixed(rl_src2, r2, r3);
52 // Compute (r1:r0) = (r1:r0) - (r3:r2)
53 OpRegReg(kOpSub, r0, r2); // r0 = r0 - r2
54 OpRegReg(kOpSbc, r1, r3); // r1 = r1 - r3 - CF
55 NewLIR2(kX86Set8R, r2, kX86CondL); // r2 = (r1:r0) < (r3:r2) ? 1 : 0
56 NewLIR2(kX86Movzx8RR, r2, r2);
57 OpReg(kOpNeg, r2); // r2 = -r2
58 OpRegReg(kOpOr, r0, r1); // r0 = high | low - sets ZF
59 NewLIR2(kX86Set8R, r0, kX86CondNz); // r0 = (r1:r0) != (r3:r2) ? 1 : 0
60 NewLIR2(kX86Movzx8RR, r0, r0);
61 OpRegReg(kOpOr, r0, r2); // r0 = r0 | r2
62 RegLocation rl_result = LocCReturn();
63 StoreValue(rl_dest, rl_result);
64}
65
66X86ConditionCode X86ConditionEncoding(ConditionCode cond) {
67 switch (cond) {
68 case kCondEq: return kX86CondEq;
69 case kCondNe: return kX86CondNe;
70 case kCondCs: return kX86CondC;
71 case kCondCc: return kX86CondNc;
72 case kCondMi: return kX86CondS;
73 case kCondPl: return kX86CondNs;
74 case kCondVs: return kX86CondO;
75 case kCondVc: return kX86CondNo;
76 case kCondHi: return kX86CondA;
77 case kCondLs: return kX86CondBe;
78 case kCondGe: return kX86CondGe;
79 case kCondLt: return kX86CondL;
80 case kCondGt: return kX86CondG;
81 case kCondLe: return kX86CondLe;
82 case kCondAl:
83 case kCondNv: LOG(FATAL) << "Should not reach here";
84 }
85 return kX86CondO;
86}
87
88LIR* X86Mir2Lir::OpCmpBranch(ConditionCode cond, int src1, int src2,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070089 LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070090 NewLIR2(kX86Cmp32RR, src1, src2);
91 X86ConditionCode cc = X86ConditionEncoding(cond);
92 LIR* branch = NewLIR2(kX86Jcc8, 0 /* lir operand for Jcc offset */ ,
93 cc);
94 branch->target = target;
95 return branch;
96}
97
98LIR* X86Mir2Lir::OpCmpImmBranch(ConditionCode cond, int reg,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070099 int check_value, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700100 if ((check_value == 0) && (cond == kCondEq || cond == kCondNe)) {
101 // TODO: when check_value == 0 and reg is rCX, use the jcxz/nz opcode
102 NewLIR2(kX86Test32RR, reg, reg);
103 } else {
104 NewLIR2(IS_SIMM8(check_value) ? kX86Cmp32RI8 : kX86Cmp32RI, reg, check_value);
105 }
106 X86ConditionCode cc = X86ConditionEncoding(cond);
107 LIR* branch = NewLIR2(kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc);
108 branch->target = target;
109 return branch;
110}
111
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700112LIR* X86Mir2Lir::OpRegCopyNoInsert(int r_dest, int r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700113 if (X86_FPREG(r_dest) || X86_FPREG(r_src))
114 return OpFpRegCopy(r_dest, r_src);
115 LIR* res = RawLIR(current_dalvik_offset_, kX86Mov32RR,
116 r_dest, r_src);
117 if (r_dest == r_src) {
118 res->flags.is_nop = true;
119 }
120 return res;
121}
122
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700123LIR* X86Mir2Lir::OpRegCopy(int r_dest, int r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700124 LIR *res = OpRegCopyNoInsert(r_dest, r_src);
125 AppendLIR(res);
126 return res;
127}
128
129void X86Mir2Lir::OpRegCopyWide(int dest_lo, int dest_hi,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700130 int src_lo, int src_hi) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700131 bool dest_fp = X86_FPREG(dest_lo) && X86_FPREG(dest_hi);
132 bool src_fp = X86_FPREG(src_lo) && X86_FPREG(src_hi);
133 assert(X86_FPREG(src_lo) == X86_FPREG(src_hi));
134 assert(X86_FPREG(dest_lo) == X86_FPREG(dest_hi));
135 if (dest_fp) {
136 if (src_fp) {
137 OpRegCopy(S2d(dest_lo, dest_hi), S2d(src_lo, src_hi));
138 } else {
139 // TODO: Prevent this from happening in the code. The result is often
140 // unused or could have been loaded more easily from memory.
141 NewLIR2(kX86MovdxrRR, dest_lo, src_lo);
142 NewLIR2(kX86MovdxrRR, dest_hi, src_hi);
143 NewLIR2(kX86PsllqRI, dest_hi, 32);
144 NewLIR2(kX86OrpsRR, dest_lo, dest_hi);
145 }
146 } else {
147 if (src_fp) {
148 NewLIR2(kX86MovdrxRR, dest_lo, src_lo);
149 NewLIR2(kX86PsrlqRI, src_lo, 32);
150 NewLIR2(kX86MovdrxRR, dest_hi, src_lo);
151 } else {
152 // Handle overlap
153 if (src_hi == dest_lo) {
154 OpRegCopy(dest_hi, src_hi);
155 OpRegCopy(dest_lo, src_lo);
156 } else {
157 OpRegCopy(dest_lo, src_lo);
158 OpRegCopy(dest_hi, src_hi);
159 }
160 }
161 }
162}
163
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700164void X86Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700165 UNIMPLEMENTED(FATAL) << "Need codegen for GenSelect";
166}
167
168void X86Mir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
buzbee0d829482013-10-11 15:24:55 -0700169 LIR* taken = &block_label_list_[bb->taken];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700170 RegLocation rl_src1 = mir_graph_->GetSrcWide(mir, 0);
171 RegLocation rl_src2 = mir_graph_->GetSrcWide(mir, 2);
172 FlushAllRegs();
173 LockCallTemps(); // Prepare for explicit register usage
174 LoadValueDirectWideFixed(rl_src1, r0, r1);
175 LoadValueDirectWideFixed(rl_src2, r2, r3);
176 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
177 // Swap operands and condition code to prevent use of zero flag.
178 if (ccode == kCondLe || ccode == kCondGt) {
179 // Compute (r3:r2) = (r3:r2) - (r1:r0)
180 OpRegReg(kOpSub, r2, r0); // r2 = r2 - r0
181 OpRegReg(kOpSbc, r3, r1); // r3 = r3 - r1 - CF
182 } else {
183 // Compute (r1:r0) = (r1:r0) - (r3:r2)
184 OpRegReg(kOpSub, r0, r2); // r0 = r0 - r2
185 OpRegReg(kOpSbc, r1, r3); // r1 = r1 - r3 - CF
186 }
187 switch (ccode) {
188 case kCondEq:
189 case kCondNe:
190 OpRegReg(kOpOr, r0, r1); // r0 = r0 | r1
191 break;
192 case kCondLe:
193 ccode = kCondGe;
194 break;
195 case kCondGt:
196 ccode = kCondLt;
197 break;
198 case kCondLt:
199 case kCondGe:
200 break;
201 default:
202 LOG(FATAL) << "Unexpected ccode: " << ccode;
203 }
204 OpCondBranch(ccode, taken);
205}
206
207RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, int reg_lo,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700208 int lit, bool is_div) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700209 LOG(FATAL) << "Unexpected use of GenDivRemLit for x86";
210 return rl_dest;
211}
212
213RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, int reg_lo,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700214 int reg_hi, bool is_div) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700215 LOG(FATAL) << "Unexpected use of GenDivRem for x86";
216 return rl_dest;
217}
218
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700219bool X86Mir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700220 DCHECK_EQ(cu_->instruction_set, kX86);
221 RegLocation rl_src1 = info->args[0];
222 RegLocation rl_src2 = info->args[1];
223 rl_src1 = LoadValue(rl_src1, kCoreReg);
224 rl_src2 = LoadValue(rl_src2, kCoreReg);
225 RegLocation rl_dest = InlineTarget(info);
226 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
227 OpRegReg(kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
228 DCHECK_EQ(cu_->instruction_set, kX86);
229 LIR* branch = NewLIR2(kX86Jcc8, 0, is_min ? kX86CondG : kX86CondL);
230 OpRegReg(kOpMov, rl_result.low_reg, rl_src1.low_reg);
231 LIR* branch2 = NewLIR1(kX86Jmp8, 0);
232 branch->target = NewLIR0(kPseudoTargetLabel);
233 OpRegReg(kOpMov, rl_result.low_reg, rl_src2.low_reg);
234 branch2->target = NewLIR0(kPseudoTargetLabel);
235 StoreValue(rl_dest, rl_result);
236 return true;
237}
238
Vladimir Markoe508a202013-11-04 15:24:22 +0000239bool X86Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
240 RegLocation rl_src_address = info->args[0]; // long address
241 rl_src_address.wide = 0; // ignore high half in info->args[1]
242 RegLocation rl_dest = InlineTarget(info);
243 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
244 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
245 if (size == kLong) {
246 // Unaligned access is allowed on x86.
247 LoadBaseDispWide(rl_address.low_reg, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
248 StoreValueWide(rl_dest, rl_result);
249 } else {
250 DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord);
251 // Unaligned access is allowed on x86.
252 LoadBaseDisp(rl_address.low_reg, 0, rl_result.low_reg, size, INVALID_SREG);
253 StoreValue(rl_dest, rl_result);
254 }
255 return true;
256}
257
258bool X86Mir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
259 RegLocation rl_src_address = info->args[0]; // long address
260 rl_src_address.wide = 0; // ignore high half in info->args[1]
261 RegLocation rl_src_value = info->args[2]; // [size] value
262 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
263 if (size == kLong) {
264 // Unaligned access is allowed on x86.
265 RegLocation rl_value = LoadValueWide(rl_src_value, kCoreReg);
266 StoreBaseDispWide(rl_address.low_reg, 0, rl_value.low_reg, rl_value.high_reg);
267 } else {
268 DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord);
269 // Unaligned access is allowed on x86.
270 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
271 StoreBaseDisp(rl_address.low_reg, 0, rl_value.low_reg, size);
272 }
273 return true;
274}
275
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700276void X86Mir2Lir::OpLea(int rBase, int reg1, int reg2, int scale, int offset) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700277 NewLIR5(kX86Lea32RA, rBase, reg1, reg2, scale, offset);
278}
279
Ian Rogers468532e2013-08-05 10:56:33 -0700280void X86Mir2Lir::OpTlsCmp(ThreadOffset offset, int val) {
281 NewLIR2(kX86Cmp16TI8, offset.Int32Value(), val);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700282}
283
Vladimir Marko1c282e22013-11-21 14:49:47 +0000284bool X86Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
Vladimir Markoc29bb612013-11-27 16:47:25 +0000285 DCHECK_EQ(cu_->instruction_set, kX86);
286 // Unused - RegLocation rl_src_unsafe = info->args[0];
287 RegLocation rl_src_obj = info->args[1]; // Object - known non-null
288 RegLocation rl_src_offset = info->args[2]; // long low
289 rl_src_offset.wide = 0; // ignore high half in info->args[3]
290 RegLocation rl_src_expected = info->args[4]; // int, long or Object
291 // If is_long, high half is in info->args[5]
292 RegLocation rl_src_new_value = info->args[is_long ? 6 : 5]; // int, long or Object
293 // If is_long, high half is in info->args[7]
294
295 if (is_long) {
Vladimir Marko70b797d2013-12-03 15:25:24 +0000296 FlushAllRegs();
297 LockCallTemps();
298 NewLIR1(kX86Push32R, rDI);
299 MarkTemp(rDI);
300 LockTemp(rDI);
301 NewLIR1(kX86Push32R, rSI);
302 MarkTemp(rSI);
303 LockTemp(rSI);
304 LoadValueDirectFixed(rl_src_obj, rDI);
305 LoadValueDirectFixed(rl_src_offset, rSI);
306 LoadValueDirectWideFixed(rl_src_expected, rAX, rDX);
307 LoadValueDirectWideFixed(rl_src_new_value, rBX, rCX);
308 NewLIR4(kX86LockCmpxchg8bA, rDI, rSI, 0, 0);
309 FreeTemp(rSI);
310 UnmarkTemp(rSI);
311 NewLIR1(kX86Pop32R, rSI);
312 FreeTemp(rDI);
313 UnmarkTemp(rDI);
314 NewLIR1(kX86Pop32R, rDI);
315 FreeCallTemps();
Vladimir Markoc29bb612013-11-27 16:47:25 +0000316 } else {
317 // EAX must hold expected for CMPXCHG. Neither rl_new_value, nor r_ptr may be in EAX.
318 FlushReg(r0);
319 LockTemp(r0);
320
321 // Release store semantics, get the barrier out of the way. TODO: revisit
322 GenMemBarrier(kStoreLoad);
323
324 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
325 RegLocation rl_new_value = LoadValue(rl_src_new_value, kCoreReg);
326
327 if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
328 // Mark card for object assuming new value is stored.
329 FreeTemp(r0); // Temporarily release EAX for MarkGCCard().
330 MarkGCCard(rl_new_value.low_reg, rl_object.low_reg);
331 LockTemp(r0);
332 }
333
334 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
335 LoadValueDirect(rl_src_expected, r0);
336 NewLIR5(kX86LockCmpxchgAR, rl_object.low_reg, rl_offset.low_reg, 0, 0, rl_new_value.low_reg);
337
338 FreeTemp(r0);
339 }
340
341 // Convert ZF to boolean
342 RegLocation rl_dest = InlineTarget(info); // boolean place for result
343 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
344 NewLIR2(kX86Set8R, rl_result.low_reg, kX86CondZ);
345 NewLIR2(kX86Movzx8RR, rl_result.low_reg, rl_result.low_reg);
346 StoreValue(rl_dest, rl_result);
347 return true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700348}
349
350LIR* X86Mir2Lir::OpPcRelLoad(int reg, LIR* target) {
351 LOG(FATAL) << "Unexpected use of OpPcRelLoad for x86";
352 return NULL;
353}
354
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700355LIR* X86Mir2Lir::OpVldm(int rBase, int count) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700356 LOG(FATAL) << "Unexpected use of OpVldm for x86";
357 return NULL;
358}
359
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700360LIR* X86Mir2Lir::OpVstm(int rBase, int count) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700361 LOG(FATAL) << "Unexpected use of OpVstm for x86";
362 return NULL;
363}
364
365void X86Mir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
366 RegLocation rl_result, int lit,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700367 int first_bit, int second_bit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700368 int t_reg = AllocTemp();
369 OpRegRegImm(kOpLsl, t_reg, rl_src.low_reg, second_bit - first_bit);
370 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, t_reg);
371 FreeTemp(t_reg);
372 if (first_bit != 0) {
373 OpRegRegImm(kOpLsl, rl_result.low_reg, rl_result.low_reg, first_bit);
374 }
375}
376
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700377void X86Mir2Lir::GenDivZeroCheck(int reg_lo, int reg_hi) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700378 int t_reg = AllocTemp();
379 OpRegRegReg(kOpOr, t_reg, reg_lo, reg_hi);
380 GenImmedCheck(kCondEq, t_reg, 0, kThrowDivZero);
381 FreeTemp(t_reg);
382}
383
384// Test suspend flag, return target of taken suspend branch
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700385LIR* X86Mir2Lir::OpTestSuspend(LIR* target) {
Ian Rogers468532e2013-08-05 10:56:33 -0700386 OpTlsCmp(Thread::ThreadFlagsOffset(), 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700387 return OpCondBranch((target == NULL) ? kCondNe : kCondEq, target);
388}
389
390// Decrement register and branch on condition
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700391LIR* X86Mir2Lir::OpDecAndBranch(ConditionCode c_code, int reg, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700392 OpRegImm(kOpSub, reg, 1);
393 return OpCmpImmBranch(c_code, reg, 0, target);
394}
395
buzbee11b63d12013-08-27 07:34:17 -0700396bool X86Mir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700397 RegLocation rl_src, RegLocation rl_dest, int lit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700398 LOG(FATAL) << "Unexpected use of smallLiteralDive in x86";
399 return false;
400}
401
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700402LIR* X86Mir2Lir::OpIT(ConditionCode cond, const char* guide) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700403 LOG(FATAL) << "Unexpected use of OpIT in x86";
404 return NULL;
405}
406
407void X86Mir2Lir::GenMulLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700408 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700409 LOG(FATAL) << "Unexpected use of GenX86Long for x86";
410}
411void X86Mir2Lir::GenAddLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700412 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700413 // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
414 // enough.
415 FlushAllRegs();
416 LockCallTemps(); // Prepare for explicit register usage
417 LoadValueDirectWideFixed(rl_src1, r0, r1);
418 LoadValueDirectWideFixed(rl_src2, r2, r3);
419 // Compute (r1:r0) = (r1:r0) + (r2:r3)
420 OpRegReg(kOpAdd, r0, r2); // r0 = r0 + r2
421 OpRegReg(kOpAdc, r1, r3); // r1 = r1 + r3 + CF
422 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
423 INVALID_SREG, INVALID_SREG};
424 StoreValueWide(rl_dest, rl_result);
425}
426
427void X86Mir2Lir::GenSubLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700428 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700429 // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
430 // enough.
431 FlushAllRegs();
432 LockCallTemps(); // Prepare for explicit register usage
433 LoadValueDirectWideFixed(rl_src1, r0, r1);
434 LoadValueDirectWideFixed(rl_src2, r2, r3);
435 // Compute (r1:r0) = (r1:r0) + (r2:r3)
436 OpRegReg(kOpSub, r0, r2); // r0 = r0 - r2
437 OpRegReg(kOpSbc, r1, r3); // r1 = r1 - r3 - CF
438 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
439 INVALID_SREG, INVALID_SREG};
440 StoreValueWide(rl_dest, rl_result);
441}
442
443void X86Mir2Lir::GenAndLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700444 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700445 // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
446 // enough.
447 FlushAllRegs();
448 LockCallTemps(); // Prepare for explicit register usage
449 LoadValueDirectWideFixed(rl_src1, r0, r1);
450 LoadValueDirectWideFixed(rl_src2, r2, r3);
451 // Compute (r1:r0) = (r1:r0) & (r2:r3)
452 OpRegReg(kOpAnd, r0, r2); // r0 = r0 & r2
453 OpRegReg(kOpAnd, r1, r3); // r1 = r1 & r3
454 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
455 INVALID_SREG, INVALID_SREG};
456 StoreValueWide(rl_dest, rl_result);
457}
458
459void X86Mir2Lir::GenOrLong(RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700460 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700461 // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
462 // enough.
463 FlushAllRegs();
464 LockCallTemps(); // Prepare for explicit register usage
465 LoadValueDirectWideFixed(rl_src1, r0, r1);
466 LoadValueDirectWideFixed(rl_src2, r2, r3);
467 // Compute (r1:r0) = (r1:r0) | (r2:r3)
468 OpRegReg(kOpOr, r0, r2); // r0 = r0 | r2
469 OpRegReg(kOpOr, r1, r3); // r1 = r1 | r3
470 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
471 INVALID_SREG, INVALID_SREG};
472 StoreValueWide(rl_dest, rl_result);
473}
474
475void X86Mir2Lir::GenXorLong(RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700476 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700477 // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
478 // enough.
479 FlushAllRegs();
480 LockCallTemps(); // Prepare for explicit register usage
481 LoadValueDirectWideFixed(rl_src1, r0, r1);
482 LoadValueDirectWideFixed(rl_src2, r2, r3);
483 // Compute (r1:r0) = (r1:r0) ^ (r2:r3)
484 OpRegReg(kOpXor, r0, r2); // r0 = r0 ^ r2
485 OpRegReg(kOpXor, r1, r3); // r1 = r1 ^ r3
486 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
487 INVALID_SREG, INVALID_SREG};
488 StoreValueWide(rl_dest, rl_result);
489}
490
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700491void X86Mir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700492 FlushAllRegs();
493 LockCallTemps(); // Prepare for explicit register usage
494 LoadValueDirectWideFixed(rl_src, r0, r1);
495 // Compute (r1:r0) = -(r1:r0)
496 OpRegReg(kOpNeg, r0, r0); // r0 = -r0
497 OpRegImm(kOpAdc, r1, 0); // r1 = r1 + CF
498 OpRegReg(kOpNeg, r1, r1); // r1 = -r1
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
Ian Rogers468532e2013-08-05 10:56:33 -0700504void X86Mir2Lir::OpRegThreadMem(OpKind op, int r_dest, ThreadOffset thread_offset) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700505 X86OpCode opcode = kX86Bkpt;
506 switch (op) {
507 case kOpCmp: opcode = kX86Cmp32RT; break;
508 case kOpMov: opcode = kX86Mov32RT; break;
509 default:
510 LOG(FATAL) << "Bad opcode: " << op;
511 break;
512 }
Ian Rogers468532e2013-08-05 10:56:33 -0700513 NewLIR2(opcode, r_dest, thread_offset.Int32Value());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700514}
515
516/*
517 * Generate array load
518 */
519void X86Mir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
Ian Rogersa9a82542013-10-04 11:17:26 -0700520 RegLocation rl_index, RegLocation rl_dest, int scale) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700521 RegisterClass reg_class = oat_reg_class_by_size(size);
522 int len_offset = mirror::Array::LengthOffset().Int32Value();
523 int data_offset;
524 RegLocation rl_result;
525 rl_array = LoadValue(rl_array, kCoreReg);
526 rl_index = LoadValue(rl_index, kCoreReg);
527
528 if (size == kLong || size == kDouble) {
529 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
530 } else {
531 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
532 }
533
534 /* null object? */
535 GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags);
536
537 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
538 /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */
539 GenRegMemCheck(kCondUge, rl_index.low_reg, rl_array.low_reg,
540 len_offset, kThrowArrayBounds);
541 }
542 if ((size == kLong) || (size == kDouble)) {
543 int reg_addr = AllocTemp();
544 OpLea(reg_addr, rl_array.low_reg, rl_index.low_reg, scale, data_offset);
545 FreeTemp(rl_array.low_reg);
546 FreeTemp(rl_index.low_reg);
547 rl_result = EvalLoc(rl_dest, reg_class, true);
548 LoadBaseIndexedDisp(reg_addr, INVALID_REG, 0, 0, rl_result.low_reg,
549 rl_result.high_reg, size, INVALID_SREG);
550 StoreValueWide(rl_dest, rl_result);
551 } else {
552 rl_result = EvalLoc(rl_dest, reg_class, true);
553
554 LoadBaseIndexedDisp(rl_array.low_reg, rl_index.low_reg, scale,
555 data_offset, rl_result.low_reg, INVALID_REG, size,
556 INVALID_SREG);
557
558 StoreValue(rl_dest, rl_result);
559 }
560}
561
562/*
563 * Generate array store
564 *
565 */
566void X86Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
Ian Rogersa9a82542013-10-04 11:17:26 -0700567 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700568 RegisterClass reg_class = oat_reg_class_by_size(size);
569 int len_offset = mirror::Array::LengthOffset().Int32Value();
570 int data_offset;
571
572 if (size == kLong || size == kDouble) {
573 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
574 } else {
575 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
576 }
577
578 rl_array = LoadValue(rl_array, kCoreReg);
579 rl_index = LoadValue(rl_index, kCoreReg);
580
581 /* null object? */
582 GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags);
583
584 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
585 /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */
586 GenRegMemCheck(kCondUge, rl_index.low_reg, rl_array.low_reg, len_offset, kThrowArrayBounds);
587 }
588 if ((size == kLong) || (size == kDouble)) {
589 rl_src = LoadValueWide(rl_src, reg_class);
590 } else {
591 rl_src = LoadValue(rl_src, reg_class);
592 }
593 // If the src reg can't be byte accessed, move it to a temp first.
594 if ((size == kSignedByte || size == kUnsignedByte) && rl_src.low_reg >= 4) {
595 int temp = AllocTemp();
596 OpRegCopy(temp, rl_src.low_reg);
597 StoreBaseIndexedDisp(rl_array.low_reg, rl_index.low_reg, scale, data_offset, temp,
598 INVALID_REG, size, INVALID_SREG);
599 } else {
600 StoreBaseIndexedDisp(rl_array.low_reg, rl_index.low_reg, scale, data_offset, rl_src.low_reg,
601 rl_src.high_reg, size, INVALID_SREG);
602 }
Ian Rogersa9a82542013-10-04 11:17:26 -0700603 if (card_mark) {
Ian Rogers773aab12013-10-14 13:50:10 -0700604 // Free rl_index if its a temp. Ensures there are 2 free regs for card mark.
605 FreeTemp(rl_index.low_reg);
Ian Rogersa9a82542013-10-04 11:17:26 -0700606 MarkGCCard(rl_src.low_reg, rl_array.low_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700607 }
608}
609
610void X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700611 RegLocation rl_src1, RegLocation rl_shift) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700612 // Default implementation is just to ignore the constant case.
613 GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
614}
615
616void X86Mir2Lir::GenArithImmOpLong(Instruction::Code opcode,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700617 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700618 // Default - bail to non-const handler.
619 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
620}
621
622} // namespace art