blob: e1bbc630de648bb99381d6b59fceaba12e28d775 [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;
Vladimir Marko58af1f92013-12-19 13:31:15 +000086 case kCondUlt: return kX86CondC;
87 case kCondUge: return kX86CondNc;
Brian Carlstrom7940e442013-07-12 13:46:57 -070088 case kCondMi: return kX86CondS;
89 case kCondPl: return kX86CondNs;
90 case kCondVs: return kX86CondO;
91 case kCondVc: return kX86CondNo;
92 case kCondHi: return kX86CondA;
93 case kCondLs: return kX86CondBe;
94 case kCondGe: return kX86CondGe;
95 case kCondLt: return kX86CondL;
96 case kCondGt: return kX86CondG;
97 case kCondLe: return kX86CondLe;
98 case kCondAl:
99 case kCondNv: LOG(FATAL) << "Should not reach here";
100 }
101 return kX86CondO;
102}
103
104LIR* X86Mir2Lir::OpCmpBranch(ConditionCode cond, int src1, int src2,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700105 LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700106 NewLIR2(kX86Cmp32RR, src1, src2);
107 X86ConditionCode cc = X86ConditionEncoding(cond);
108 LIR* branch = NewLIR2(kX86Jcc8, 0 /* lir operand for Jcc offset */ ,
109 cc);
110 branch->target = target;
111 return branch;
112}
113
114LIR* X86Mir2Lir::OpCmpImmBranch(ConditionCode cond, int reg,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700115 int check_value, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700116 if ((check_value == 0) && (cond == kCondEq || cond == kCondNe)) {
117 // TODO: when check_value == 0 and reg is rCX, use the jcxz/nz opcode
118 NewLIR2(kX86Test32RR, reg, reg);
119 } else {
120 NewLIR2(IS_SIMM8(check_value) ? kX86Cmp32RI8 : kX86Cmp32RI, reg, check_value);
121 }
122 X86ConditionCode cc = X86ConditionEncoding(cond);
123 LIR* branch = NewLIR2(kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc);
124 branch->target = target;
125 return branch;
126}
127
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700128LIR* X86Mir2Lir::OpRegCopyNoInsert(int r_dest, int r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700129 if (X86_FPREG(r_dest) || X86_FPREG(r_src))
130 return OpFpRegCopy(r_dest, r_src);
131 LIR* res = RawLIR(current_dalvik_offset_, kX86Mov32RR,
132 r_dest, r_src);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800133 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700134 res->flags.is_nop = true;
135 }
136 return res;
137}
138
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700139LIR* X86Mir2Lir::OpRegCopy(int r_dest, int r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700140 LIR *res = OpRegCopyNoInsert(r_dest, r_src);
141 AppendLIR(res);
142 return res;
143}
144
145void X86Mir2Lir::OpRegCopyWide(int dest_lo, int dest_hi,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700146 int src_lo, int src_hi) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700147 bool dest_fp = X86_FPREG(dest_lo) && X86_FPREG(dest_hi);
148 bool src_fp = X86_FPREG(src_lo) && X86_FPREG(src_hi);
149 assert(X86_FPREG(src_lo) == X86_FPREG(src_hi));
150 assert(X86_FPREG(dest_lo) == X86_FPREG(dest_hi));
151 if (dest_fp) {
152 if (src_fp) {
153 OpRegCopy(S2d(dest_lo, dest_hi), S2d(src_lo, src_hi));
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(kX86MovdxrRR, dest_lo, src_lo);
Bill Buzbeed61ba4b2014-01-13 21:44:01 +0000158 dest_hi = AllocTempDouble();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700159 NewLIR2(kX86MovdxrRR, dest_hi, src_hi);
160 NewLIR2(kX86PsllqRI, dest_hi, 32);
161 NewLIR2(kX86OrpsRR, dest_lo, dest_hi);
Bill Buzbeed61ba4b2014-01-13 21:44:01 +0000162 FreeTemp(dest_hi);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700163 }
164 } else {
165 if (src_fp) {
166 NewLIR2(kX86MovdrxRR, dest_lo, src_lo);
167 NewLIR2(kX86PsrlqRI, src_lo, 32);
168 NewLIR2(kX86MovdrxRR, dest_hi, src_lo);
169 } else {
170 // Handle overlap
171 if (src_hi == dest_lo) {
172 OpRegCopy(dest_hi, src_hi);
173 OpRegCopy(dest_lo, src_lo);
174 } else {
175 OpRegCopy(dest_lo, src_lo);
176 OpRegCopy(dest_hi, src_hi);
177 }
178 }
179 }
180}
181
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700182void X86Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700183 UNIMPLEMENTED(FATAL) << "Need codegen for GenSelect";
184}
185
186void X86Mir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
buzbee0d829482013-10-11 15:24:55 -0700187 LIR* taken = &block_label_list_[bb->taken];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700188 RegLocation rl_src1 = mir_graph_->GetSrcWide(mir, 0);
189 RegLocation rl_src2 = mir_graph_->GetSrcWide(mir, 2);
Mark Mendell412d4f82013-12-18 13:32:36 -0800190 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
191
192 if (rl_src1.is_const) {
193 std::swap(rl_src1, rl_src2);
194 ccode = FlipComparisonOrder(ccode);
195 }
196 if (rl_src2.is_const) {
197 // Do special compare/branch against simple const operand
198 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
199 GenFusedLongCmpImmBranch(bb, rl_src1, val, ccode);
200 return;
201 }
202
Brian Carlstrom7940e442013-07-12 13:46:57 -0700203 FlushAllRegs();
204 LockCallTemps(); // Prepare for explicit register usage
205 LoadValueDirectWideFixed(rl_src1, r0, r1);
206 LoadValueDirectWideFixed(rl_src2, r2, r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700207 // Swap operands and condition code to prevent use of zero flag.
208 if (ccode == kCondLe || ccode == kCondGt) {
209 // Compute (r3:r2) = (r3:r2) - (r1:r0)
210 OpRegReg(kOpSub, r2, r0); // r2 = r2 - r0
211 OpRegReg(kOpSbc, r3, r1); // r3 = r3 - r1 - CF
212 } else {
213 // Compute (r1:r0) = (r1:r0) - (r3:r2)
214 OpRegReg(kOpSub, r0, r2); // r0 = r0 - r2
215 OpRegReg(kOpSbc, r1, r3); // r1 = r1 - r3 - CF
216 }
217 switch (ccode) {
218 case kCondEq:
219 case kCondNe:
220 OpRegReg(kOpOr, r0, r1); // r0 = r0 | r1
221 break;
222 case kCondLe:
223 ccode = kCondGe;
224 break;
225 case kCondGt:
226 ccode = kCondLt;
227 break;
228 case kCondLt:
229 case kCondGe:
230 break;
231 default:
232 LOG(FATAL) << "Unexpected ccode: " << ccode;
233 }
234 OpCondBranch(ccode, taken);
235}
236
Mark Mendell412d4f82013-12-18 13:32:36 -0800237void X86Mir2Lir::GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1,
238 int64_t val, ConditionCode ccode) {
239 int32_t val_lo = Low32Bits(val);
240 int32_t val_hi = High32Bits(val);
241 LIR* taken = &block_label_list_[bb->taken];
242 LIR* not_taken = &block_label_list_[bb->fall_through];
243 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
244 int32_t low_reg = rl_src1.low_reg;
245 int32_t high_reg = rl_src1.high_reg;
246
247 if (val == 0 && (ccode == kCondEq || ccode == kCondNe)) {
248 int t_reg = AllocTemp();
249 OpRegRegReg(kOpOr, t_reg, low_reg, high_reg);
250 FreeTemp(t_reg);
251 OpCondBranch(ccode, taken);
252 return;
253 }
254
255 OpRegImm(kOpCmp, high_reg, val_hi);
256 switch (ccode) {
257 case kCondEq:
258 case kCondNe:
259 OpCondBranch(kCondNe, (ccode == kCondEq) ? not_taken : taken);
260 break;
261 case kCondLt:
262 OpCondBranch(kCondLt, taken);
263 OpCondBranch(kCondGt, not_taken);
264 ccode = kCondUlt;
265 break;
266 case kCondLe:
267 OpCondBranch(kCondLt, taken);
268 OpCondBranch(kCondGt, not_taken);
269 ccode = kCondLs;
270 break;
271 case kCondGt:
272 OpCondBranch(kCondGt, taken);
273 OpCondBranch(kCondLt, not_taken);
274 ccode = kCondHi;
275 break;
276 case kCondGe:
277 OpCondBranch(kCondGt, taken);
278 OpCondBranch(kCondLt, not_taken);
279 ccode = kCondUge;
280 break;
281 default:
282 LOG(FATAL) << "Unexpected ccode: " << ccode;
283 }
284 OpCmpImmBranch(ccode, low_reg, val_lo, taken);
285}
286
Brian Carlstrom7940e442013-07-12 13:46:57 -0700287RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, int reg_lo,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700288 int lit, bool is_div) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700289 LOG(FATAL) << "Unexpected use of GenDivRemLit for x86";
290 return rl_dest;
291}
292
293RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, int reg_lo,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700294 int reg_hi, bool is_div) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700295 LOG(FATAL) << "Unexpected use of GenDivRem for x86";
296 return rl_dest;
297}
298
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700299bool X86Mir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700300 DCHECK_EQ(cu_->instruction_set, kX86);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800301
302 // Get the two arguments to the invoke and place them in GP registers.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700303 RegLocation rl_src1 = info->args[0];
304 RegLocation rl_src2 = info->args[1];
305 rl_src1 = LoadValue(rl_src1, kCoreReg);
306 rl_src2 = LoadValue(rl_src2, kCoreReg);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800307
Brian Carlstrom7940e442013-07-12 13:46:57 -0700308 RegLocation rl_dest = InlineTarget(info);
309 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800310
311 /*
312 * If the result register is the same as the second element, then we need to be careful.
313 * The reason is that the first copy will inadvertently clobber the second element with
314 * the first one thus yielding the wrong result. Thus we do a swap in that case.
315 */
316 if (rl_result.low_reg == rl_src2.low_reg) {
317 std::swap(rl_src1, rl_src2);
318 }
319
320 // Pick the first integer as min/max.
321 OpRegCopy(rl_result.low_reg, rl_src1.low_reg);
322
323 // If the integers are both in the same register, then there is nothing else to do
324 // because they are equal and we have already moved one into the result.
325 if (rl_src1.low_reg != rl_src2.low_reg) {
326 // It is possible we didn't pick correctly so do the actual comparison now.
327 OpRegReg(kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
328
329 // Conditionally move the other integer into the destination register.
330 ConditionCode condition_code = is_min ? kCondGt : kCondLt;
331 OpCondRegReg(kOpCmov, condition_code, rl_result.low_reg, rl_src2.low_reg);
332 }
333
Brian Carlstrom7940e442013-07-12 13:46:57 -0700334 StoreValue(rl_dest, rl_result);
335 return true;
336}
337
Vladimir Markoe508a202013-11-04 15:24:22 +0000338bool X86Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
339 RegLocation rl_src_address = info->args[0]; // long address
340 rl_src_address.wide = 0; // ignore high half in info->args[1]
341 RegLocation rl_dest = InlineTarget(info);
342 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
343 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
344 if (size == kLong) {
345 // Unaligned access is allowed on x86.
346 LoadBaseDispWide(rl_address.low_reg, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
347 StoreValueWide(rl_dest, rl_result);
348 } else {
349 DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord);
350 // Unaligned access is allowed on x86.
351 LoadBaseDisp(rl_address.low_reg, 0, rl_result.low_reg, size, INVALID_SREG);
352 StoreValue(rl_dest, rl_result);
353 }
354 return true;
355}
356
357bool X86Mir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
358 RegLocation rl_src_address = info->args[0]; // long address
359 rl_src_address.wide = 0; // ignore high half in info->args[1]
360 RegLocation rl_src_value = info->args[2]; // [size] value
361 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
362 if (size == kLong) {
363 // Unaligned access is allowed on x86.
364 RegLocation rl_value = LoadValueWide(rl_src_value, kCoreReg);
365 StoreBaseDispWide(rl_address.low_reg, 0, rl_value.low_reg, rl_value.high_reg);
366 } else {
367 DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord);
368 // Unaligned access is allowed on x86.
369 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
370 StoreBaseDisp(rl_address.low_reg, 0, rl_value.low_reg, size);
371 }
372 return true;
373}
374
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700375void X86Mir2Lir::OpLea(int rBase, int reg1, int reg2, int scale, int offset) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700376 NewLIR5(kX86Lea32RA, rBase, reg1, reg2, scale, offset);
377}
378
Ian Rogers468532e2013-08-05 10:56:33 -0700379void X86Mir2Lir::OpTlsCmp(ThreadOffset offset, int val) {
380 NewLIR2(kX86Cmp16TI8, offset.Int32Value(), val);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700381}
382
Vladimir Marko1c282e22013-11-21 14:49:47 +0000383bool X86Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
Vladimir Markoc29bb612013-11-27 16:47:25 +0000384 DCHECK_EQ(cu_->instruction_set, kX86);
385 // Unused - RegLocation rl_src_unsafe = info->args[0];
386 RegLocation rl_src_obj = info->args[1]; // Object - known non-null
387 RegLocation rl_src_offset = info->args[2]; // long low
388 rl_src_offset.wide = 0; // ignore high half in info->args[3]
389 RegLocation rl_src_expected = info->args[4]; // int, long or Object
390 // If is_long, high half is in info->args[5]
391 RegLocation rl_src_new_value = info->args[is_long ? 6 : 5]; // int, long or Object
392 // If is_long, high half is in info->args[7]
393
394 if (is_long) {
Vladimir Marko70b797d2013-12-03 15:25:24 +0000395 FlushAllRegs();
396 LockCallTemps();
Vladimir Markoa6fd8ba2013-12-13 10:53:49 +0000397 LoadValueDirectWideFixed(rl_src_expected, rAX, rDX);
398 LoadValueDirectWideFixed(rl_src_new_value, rBX, rCX);
Vladimir Marko70b797d2013-12-03 15:25:24 +0000399 NewLIR1(kX86Push32R, rDI);
400 MarkTemp(rDI);
401 LockTemp(rDI);
402 NewLIR1(kX86Push32R, rSI);
403 MarkTemp(rSI);
404 LockTemp(rSI);
Vladimir Markoa6fd8ba2013-12-13 10:53:49 +0000405 const int push_offset = 4 /* push edi */ + 4 /* push esi */;
406 LoadWordDisp(TargetReg(kSp), SRegOffset(rl_src_obj.s_reg_low) + push_offset, rDI);
407 LoadWordDisp(TargetReg(kSp), SRegOffset(rl_src_offset.s_reg_low) + push_offset, rSI);
Vladimir Marko70b797d2013-12-03 15:25:24 +0000408 NewLIR4(kX86LockCmpxchg8bA, rDI, rSI, 0, 0);
409 FreeTemp(rSI);
410 UnmarkTemp(rSI);
411 NewLIR1(kX86Pop32R, rSI);
412 FreeTemp(rDI);
413 UnmarkTemp(rDI);
414 NewLIR1(kX86Pop32R, rDI);
415 FreeCallTemps();
Vladimir Markoc29bb612013-11-27 16:47:25 +0000416 } else {
417 // EAX must hold expected for CMPXCHG. Neither rl_new_value, nor r_ptr may be in EAX.
418 FlushReg(r0);
419 LockTemp(r0);
420
421 // Release store semantics, get the barrier out of the way. TODO: revisit
422 GenMemBarrier(kStoreLoad);
423
424 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
425 RegLocation rl_new_value = LoadValue(rl_src_new_value, kCoreReg);
426
427 if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
428 // Mark card for object assuming new value is stored.
429 FreeTemp(r0); // Temporarily release EAX for MarkGCCard().
430 MarkGCCard(rl_new_value.low_reg, rl_object.low_reg);
431 LockTemp(r0);
432 }
433
434 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
435 LoadValueDirect(rl_src_expected, r0);
436 NewLIR5(kX86LockCmpxchgAR, rl_object.low_reg, rl_offset.low_reg, 0, 0, rl_new_value.low_reg);
437
438 FreeTemp(r0);
439 }
440
441 // Convert ZF to boolean
442 RegLocation rl_dest = InlineTarget(info); // boolean place for result
443 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
444 NewLIR2(kX86Set8R, rl_result.low_reg, kX86CondZ);
445 NewLIR2(kX86Movzx8RR, rl_result.low_reg, rl_result.low_reg);
446 StoreValue(rl_dest, rl_result);
447 return true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700448}
449
450LIR* X86Mir2Lir::OpPcRelLoad(int reg, LIR* target) {
451 LOG(FATAL) << "Unexpected use of OpPcRelLoad for x86";
452 return NULL;
453}
454
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700455LIR* X86Mir2Lir::OpVldm(int rBase, int count) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700456 LOG(FATAL) << "Unexpected use of OpVldm for x86";
457 return NULL;
458}
459
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700460LIR* X86Mir2Lir::OpVstm(int rBase, int count) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700461 LOG(FATAL) << "Unexpected use of OpVstm for x86";
462 return NULL;
463}
464
465void X86Mir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
466 RegLocation rl_result, int lit,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700467 int first_bit, int second_bit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700468 int t_reg = AllocTemp();
469 OpRegRegImm(kOpLsl, t_reg, rl_src.low_reg, second_bit - first_bit);
470 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, t_reg);
471 FreeTemp(t_reg);
472 if (first_bit != 0) {
473 OpRegRegImm(kOpLsl, rl_result.low_reg, rl_result.low_reg, first_bit);
474 }
475}
476
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700477void X86Mir2Lir::GenDivZeroCheck(int reg_lo, int reg_hi) {
Razvan A Lupusoru090dd442013-12-20 14:35:03 -0800478 // We are not supposed to clobber either of the provided registers, so allocate
479 // a temporary to use for the check.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700480 int t_reg = AllocTemp();
Razvan A Lupusoru090dd442013-12-20 14:35:03 -0800481
482 // Doing an OR is a quick way to check if both registers are zero. This will set the flags.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700483 OpRegRegReg(kOpOr, t_reg, reg_lo, reg_hi);
Razvan A Lupusoru090dd442013-12-20 14:35:03 -0800484
485 // In case of zero, throw ArithmeticException.
486 GenCheck(kCondEq, kThrowDivZero);
487
488 // The temp is no longer needed so free it at this time.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700489 FreeTemp(t_reg);
490}
491
492// Test suspend flag, return target of taken suspend branch
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700493LIR* X86Mir2Lir::OpTestSuspend(LIR* target) {
Ian Rogers468532e2013-08-05 10:56:33 -0700494 OpTlsCmp(Thread::ThreadFlagsOffset(), 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700495 return OpCondBranch((target == NULL) ? kCondNe : kCondEq, target);
496}
497
498// Decrement register and branch on condition
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700499LIR* X86Mir2Lir::OpDecAndBranch(ConditionCode c_code, int reg, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700500 OpRegImm(kOpSub, reg, 1);
501 return OpCmpImmBranch(c_code, reg, 0, target);
502}
503
buzbee11b63d12013-08-27 07:34:17 -0700504bool X86Mir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700505 RegLocation rl_src, RegLocation rl_dest, int lit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700506 LOG(FATAL) << "Unexpected use of smallLiteralDive in x86";
507 return false;
508}
509
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700510LIR* X86Mir2Lir::OpIT(ConditionCode cond, const char* guide) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700511 LOG(FATAL) << "Unexpected use of OpIT in x86";
512 return NULL;
513}
514
Mark Mendelle02d48f2014-01-15 11:19:23 -0800515void X86Mir2Lir::GenMulLong(Instruction::Code, RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700516 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700517 LOG(FATAL) << "Unexpected use of GenX86Long for x86";
518}
Mark Mendelle02d48f2014-01-15 11:19:23 -0800519
520void X86Mir2Lir::GenLongRegOrMemOp(RegLocation rl_dest, RegLocation rl_src,
521 Instruction::Code op) {
522 DCHECK_EQ(rl_dest.location, kLocPhysReg);
523 X86OpCode x86op = GetOpcode(op, rl_dest, rl_src, false);
524 if (rl_src.location == kLocPhysReg) {
525 // Both operands are in registers.
526 if (rl_dest.low_reg == rl_src.high_reg) {
527 // The registers are the same, so we would clobber it before the use.
528 int temp_reg = AllocTemp();
529 OpRegCopy(temp_reg, rl_dest.low_reg);
530 rl_src.high_reg = temp_reg;
531 }
532 NewLIR2(x86op, rl_dest.low_reg, rl_src.low_reg);
533
534 x86op = GetOpcode(op, rl_dest, rl_src, true);
535 NewLIR2(x86op, rl_dest.high_reg, rl_src.high_reg);
536 FreeTemp(rl_src.low_reg);
537 FreeTemp(rl_src.high_reg);
538 return;
539 }
540
541 // RHS is in memory.
542 DCHECK((rl_src.location == kLocDalvikFrame) ||
543 (rl_src.location == kLocCompilerTemp));
544 int rBase = TargetReg(kSp);
545 int displacement = SRegOffset(rl_src.s_reg_low);
546
547 LIR *lir = NewLIR3(x86op, rl_dest.low_reg, rBase, displacement + LOWORD_OFFSET);
548 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
549 true /* is_load */, true /* is64bit */);
550 x86op = GetOpcode(op, rl_dest, rl_src, true);
551 lir = NewLIR3(x86op, rl_dest.high_reg, rBase, displacement + HIWORD_OFFSET);
552 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
553 true /* is_load */, true /* is64bit */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700554}
555
Mark Mendelle02d48f2014-01-15 11:19:23 -0800556void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op) {
557 rl_dest = UpdateLocWide(rl_dest);
558 if (rl_dest.location == kLocPhysReg) {
559 // Ensure we are in a register pair
560 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
561
562 rl_src = UpdateLocWide(rl_src);
563 GenLongRegOrMemOp(rl_result, rl_src, op);
564 StoreFinalValueWide(rl_dest, rl_result);
565 return;
566 }
567
568 // It wasn't in registers, so it better be in memory.
569 DCHECK((rl_dest.location == kLocDalvikFrame) ||
570 (rl_dest.location == kLocCompilerTemp));
571 rl_src = LoadValueWide(rl_src, kCoreReg);
572
573 // Operate directly into memory.
574 X86OpCode x86op = GetOpcode(op, rl_dest, rl_src, false);
575 int rBase = TargetReg(kSp);
576 int displacement = SRegOffset(rl_dest.s_reg_low);
577
578 LIR *lir = NewLIR3(x86op, rBase, displacement + LOWORD_OFFSET, rl_src.low_reg);
579 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
580 false /* is_load */, true /* is64bit */);
581 x86op = GetOpcode(op, rl_dest, rl_src, true);
582 lir = NewLIR3(x86op, rBase, displacement + HIWORD_OFFSET, rl_src.high_reg);
583 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
584 false /* is_load */, true /* is64bit */);
585 FreeTemp(rl_src.low_reg);
586 FreeTemp(rl_src.high_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700587}
588
Mark Mendelle02d48f2014-01-15 11:19:23 -0800589void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src1,
590 RegLocation rl_src2, Instruction::Code op,
591 bool is_commutative) {
592 // Is this really a 2 operand operation?
593 switch (op) {
594 case Instruction::ADD_LONG_2ADDR:
595 case Instruction::SUB_LONG_2ADDR:
596 case Instruction::AND_LONG_2ADDR:
597 case Instruction::OR_LONG_2ADDR:
598 case Instruction::XOR_LONG_2ADDR:
599 GenLongArith(rl_dest, rl_src2, op);
600 return;
601 default:
602 break;
603 }
604
605 if (rl_dest.location == kLocPhysReg) {
606 RegLocation rl_result = LoadValueWide(rl_src1, kCoreReg);
607
608 // We are about to clobber the LHS, so it needs to be a temp.
609 rl_result = ForceTempWide(rl_result);
610
611 // Perform the operation using the RHS.
612 rl_src2 = UpdateLocWide(rl_src2);
613 GenLongRegOrMemOp(rl_result, rl_src2, op);
614
615 // And now record that the result is in the temp.
616 StoreFinalValueWide(rl_dest, rl_result);
617 return;
618 }
619
620 // It wasn't in registers, so it better be in memory.
621 DCHECK((rl_dest.location == kLocDalvikFrame) ||
622 (rl_dest.location == kLocCompilerTemp));
623 rl_src1 = UpdateLocWide(rl_src1);
624 rl_src2 = UpdateLocWide(rl_src2);
625
626 // Get one of the source operands into temporary register.
627 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
628 if (IsTemp(rl_src1.low_reg) && IsTemp(rl_src1.high_reg)) {
629 GenLongRegOrMemOp(rl_src1, rl_src2, op);
630 } else if (is_commutative) {
631 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
632 // We need at least one of them to be a temporary.
633 if (!(IsTemp(rl_src2.low_reg) && IsTemp(rl_src2.high_reg))) {
634 rl_src1 = ForceTempWide(rl_src1);
635 }
636 GenLongRegOrMemOp(rl_src1, rl_src2, op);
637 } else {
638 // Need LHS to be the temp.
639 rl_src1 = ForceTempWide(rl_src1);
640 GenLongRegOrMemOp(rl_src1, rl_src2, op);
641 }
642
643 StoreFinalValueWide(rl_dest, rl_src1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700644}
645
Mark Mendelle02d48f2014-01-15 11:19:23 -0800646void X86Mir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700647 RegLocation rl_src1, RegLocation rl_src2) {
Mark Mendelle02d48f2014-01-15 11:19:23 -0800648 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
649}
650
651void X86Mir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest,
652 RegLocation rl_src1, RegLocation rl_src2) {
653 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, false);
654}
655
656void X86Mir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest,
657 RegLocation rl_src1, RegLocation rl_src2) {
658 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
659}
660
661void X86Mir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest,
662 RegLocation rl_src1, RegLocation rl_src2) {
663 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
664}
665
666void X86Mir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest,
667 RegLocation rl_src1, RegLocation rl_src2) {
668 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700669}
670
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700671void X86Mir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
Mark Mendelle02d48f2014-01-15 11:19:23 -0800672 rl_src = LoadValueWide(rl_src, kCoreReg);
673 RegLocation rl_result = ForceTempWide(rl_src);
674 if (rl_dest.low_reg == rl_src.high_reg) {
675 // The registers are the same, so we would clobber it before the use.
676 int temp_reg = AllocTemp();
677 OpRegCopy(temp_reg, rl_result.low_reg);
678 rl_result.high_reg = temp_reg;
679 }
680 OpRegReg(kOpNeg, rl_result.low_reg, rl_result.low_reg); // rLow = -rLow
681 OpRegImm(kOpAdc, rl_result.high_reg, 0); // rHigh = rHigh + CF
682 OpRegReg(kOpNeg, rl_result.high_reg, rl_result.high_reg); // rHigh = -rHigh
Brian Carlstrom7940e442013-07-12 13:46:57 -0700683 StoreValueWide(rl_dest, rl_result);
684}
685
Ian Rogers468532e2013-08-05 10:56:33 -0700686void X86Mir2Lir::OpRegThreadMem(OpKind op, int r_dest, ThreadOffset thread_offset) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700687 X86OpCode opcode = kX86Bkpt;
688 switch (op) {
689 case kOpCmp: opcode = kX86Cmp32RT; break;
690 case kOpMov: opcode = kX86Mov32RT; break;
691 default:
692 LOG(FATAL) << "Bad opcode: " << op;
693 break;
694 }
Ian Rogers468532e2013-08-05 10:56:33 -0700695 NewLIR2(opcode, r_dest, thread_offset.Int32Value());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700696}
697
698/*
699 * Generate array load
700 */
701void X86Mir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
Ian Rogersa9a82542013-10-04 11:17:26 -0700702 RegLocation rl_index, RegLocation rl_dest, int scale) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700703 RegisterClass reg_class = oat_reg_class_by_size(size);
704 int len_offset = mirror::Array::LengthOffset().Int32Value();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700705 RegLocation rl_result;
706 rl_array = LoadValue(rl_array, kCoreReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700707
Mark Mendell343adb52013-12-18 06:02:17 -0800708 int data_offset;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700709 if (size == kLong || size == kDouble) {
710 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
711 } else {
712 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
713 }
714
Mark Mendell343adb52013-12-18 06:02:17 -0800715 bool constant_index = rl_index.is_const;
716 int32_t constant_index_value = 0;
717 if (!constant_index) {
718 rl_index = LoadValue(rl_index, kCoreReg);
719 } else {
720 constant_index_value = mir_graph_->ConstantValue(rl_index);
721 // If index is constant, just fold it into the data offset
722 data_offset += constant_index_value << scale;
723 // treat as non array below
724 rl_index.low_reg = INVALID_REG;
725 }
726
Brian Carlstrom7940e442013-07-12 13:46:57 -0700727 /* null object? */
728 GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags);
729
730 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
Mark Mendell343adb52013-12-18 06:02:17 -0800731 if (constant_index) {
732 GenMemImmedCheck(kCondLs, rl_array.low_reg, len_offset,
733 constant_index_value, kThrowConstantArrayBounds);
734 } else {
735 GenRegMemCheck(kCondUge, rl_index.low_reg, rl_array.low_reg,
736 len_offset, kThrowArrayBounds);
737 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700738 }
Mark Mendell343adb52013-12-18 06:02:17 -0800739 rl_result = EvalLoc(rl_dest, reg_class, true);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700740 if ((size == kLong) || (size == kDouble)) {
Mark Mendell343adb52013-12-18 06:02:17 -0800741 LoadBaseIndexedDisp(rl_array.low_reg, rl_index.low_reg, scale, data_offset, rl_result.low_reg,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700742 rl_result.high_reg, size, INVALID_SREG);
743 StoreValueWide(rl_dest, rl_result);
744 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700745 LoadBaseIndexedDisp(rl_array.low_reg, rl_index.low_reg, scale,
746 data_offset, rl_result.low_reg, INVALID_REG, size,
747 INVALID_SREG);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700748 StoreValue(rl_dest, rl_result);
749 }
750}
751
752/*
753 * Generate array store
754 *
755 */
756void X86Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
Ian Rogersa9a82542013-10-04 11:17:26 -0700757 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700758 RegisterClass reg_class = oat_reg_class_by_size(size);
759 int len_offset = mirror::Array::LengthOffset().Int32Value();
760 int data_offset;
761
762 if (size == kLong || size == kDouble) {
763 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
764 } else {
765 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
766 }
767
768 rl_array = LoadValue(rl_array, kCoreReg);
Mark Mendell343adb52013-12-18 06:02:17 -0800769 bool constant_index = rl_index.is_const;
770 int32_t constant_index_value = 0;
771 if (!constant_index) {
772 rl_index = LoadValue(rl_index, kCoreReg);
773 } else {
774 // If index is constant, just fold it into the data offset
775 constant_index_value = mir_graph_->ConstantValue(rl_index);
776 data_offset += constant_index_value << scale;
777 // treat as non array below
778 rl_index.low_reg = INVALID_REG;
779 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700780
781 /* null object? */
782 GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags);
783
784 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
Mark Mendell343adb52013-12-18 06:02:17 -0800785 if (constant_index) {
786 GenMemImmedCheck(kCondLs, rl_array.low_reg, len_offset,
787 constant_index_value, kThrowConstantArrayBounds);
788 } else {
789 GenRegMemCheck(kCondUge, rl_index.low_reg, rl_array.low_reg,
790 len_offset, kThrowArrayBounds);
791 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700792 }
793 if ((size == kLong) || (size == kDouble)) {
794 rl_src = LoadValueWide(rl_src, reg_class);
795 } else {
796 rl_src = LoadValue(rl_src, reg_class);
797 }
798 // If the src reg can't be byte accessed, move it to a temp first.
799 if ((size == kSignedByte || size == kUnsignedByte) && rl_src.low_reg >= 4) {
800 int temp = AllocTemp();
801 OpRegCopy(temp, rl_src.low_reg);
802 StoreBaseIndexedDisp(rl_array.low_reg, rl_index.low_reg, scale, data_offset, temp,
803 INVALID_REG, size, INVALID_SREG);
804 } else {
805 StoreBaseIndexedDisp(rl_array.low_reg, rl_index.low_reg, scale, data_offset, rl_src.low_reg,
806 rl_src.high_reg, size, INVALID_SREG);
807 }
Ian Rogersa9a82542013-10-04 11:17:26 -0700808 if (card_mark) {
Ian Rogers773aab12013-10-14 13:50:10 -0700809 // Free rl_index if its a temp. Ensures there are 2 free regs for card mark.
Mark Mendell343adb52013-12-18 06:02:17 -0800810 if (!constant_index) {
811 FreeTemp(rl_index.low_reg);
812 }
Ian Rogersa9a82542013-10-04 11:17:26 -0700813 MarkGCCard(rl_src.low_reg, rl_array.low_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700814 }
815}
816
817void X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700818 RegLocation rl_src1, RegLocation rl_shift) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700819 // Default implementation is just to ignore the constant case.
820 GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
821}
822
823void X86Mir2Lir::GenArithImmOpLong(Instruction::Code opcode,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700824 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
Mark Mendelle02d48f2014-01-15 11:19:23 -0800825 switch (opcode) {
826 case Instruction::ADD_LONG:
827 case Instruction::AND_LONG:
828 case Instruction::OR_LONG:
829 case Instruction::XOR_LONG:
830 if (rl_src2.is_const) {
831 GenLongLongImm(rl_dest, rl_src1, rl_src2, opcode);
832 } else {
833 DCHECK(rl_src1.is_const);
834 GenLongLongImm(rl_dest, rl_src2, rl_src1, opcode);
835 }
836 break;
837 case Instruction::SUB_LONG:
838 case Instruction::SUB_LONG_2ADDR:
839 if (rl_src2.is_const) {
840 GenLongLongImm(rl_dest, rl_src1, rl_src2, opcode);
841 } else {
842 GenSubLong(opcode, rl_dest, rl_src1, rl_src2);
843 }
844 break;
845 case Instruction::ADD_LONG_2ADDR:
846 case Instruction::OR_LONG_2ADDR:
847 case Instruction::XOR_LONG_2ADDR:
848 case Instruction::AND_LONG_2ADDR:
849 if (rl_src2.is_const) {
850 GenLongImm(rl_dest, rl_src2, opcode);
851 } else {
852 DCHECK(rl_src1.is_const);
853 GenLongLongImm(rl_dest, rl_src2, rl_src1, opcode);
854 }
855 break;
856 default:
857 // Default - bail to non-const handler.
858 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
859 break;
860 }
861}
862
863bool X86Mir2Lir::IsNoOp(Instruction::Code op, int32_t value) {
864 switch (op) {
865 case Instruction::AND_LONG_2ADDR:
866 case Instruction::AND_LONG:
867 return value == -1;
868 case Instruction::OR_LONG:
869 case Instruction::OR_LONG_2ADDR:
870 case Instruction::XOR_LONG:
871 case Instruction::XOR_LONG_2ADDR:
872 return value == 0;
873 default:
874 return false;
875 }
876}
877
878X86OpCode X86Mir2Lir::GetOpcode(Instruction::Code op, RegLocation dest, RegLocation rhs,
879 bool is_high_op) {
880 bool rhs_in_mem = rhs.location != kLocPhysReg;
881 bool dest_in_mem = dest.location != kLocPhysReg;
882 DCHECK(!rhs_in_mem || !dest_in_mem);
883 switch (op) {
884 case Instruction::ADD_LONG:
885 case Instruction::ADD_LONG_2ADDR:
886 if (dest_in_mem) {
887 return is_high_op ? kX86Adc32MR : kX86Add32MR;
888 } else if (rhs_in_mem) {
889 return is_high_op ? kX86Adc32RM : kX86Add32RM;
890 }
891 return is_high_op ? kX86Adc32RR : kX86Add32RR;
892 case Instruction::SUB_LONG:
893 case Instruction::SUB_LONG_2ADDR:
894 if (dest_in_mem) {
895 return is_high_op ? kX86Sbb32MR : kX86Sub32MR;
896 } else if (rhs_in_mem) {
897 return is_high_op ? kX86Sbb32RM : kX86Sub32RM;
898 }
899 return is_high_op ? kX86Sbb32RR : kX86Sub32RR;
900 case Instruction::AND_LONG_2ADDR:
901 case Instruction::AND_LONG:
902 if (dest_in_mem) {
903 return kX86And32MR;
904 }
905 return rhs_in_mem ? kX86And32RM : kX86And32RR;
906 case Instruction::OR_LONG:
907 case Instruction::OR_LONG_2ADDR:
908 if (dest_in_mem) {
909 return kX86Or32MR;
910 }
911 return rhs_in_mem ? kX86Or32RM : kX86Or32RR;
912 case Instruction::XOR_LONG:
913 case Instruction::XOR_LONG_2ADDR:
914 if (dest_in_mem) {
915 return kX86Xor32MR;
916 }
917 return rhs_in_mem ? kX86Xor32RM : kX86Xor32RR;
918 default:
919 LOG(FATAL) << "Unexpected opcode: " << op;
920 return kX86Add32RR;
921 }
922}
923
924X86OpCode X86Mir2Lir::GetOpcode(Instruction::Code op, RegLocation loc, bool is_high_op,
925 int32_t value) {
926 bool in_mem = loc.location != kLocPhysReg;
927 bool byte_imm = IS_SIMM8(value);
928 DCHECK(in_mem || !IsFpReg(loc.low_reg));
929 switch (op) {
930 case Instruction::ADD_LONG:
931 case Instruction::ADD_LONG_2ADDR:
932 if (byte_imm) {
933 if (in_mem) {
934 return is_high_op ? kX86Adc32MI8 : kX86Add32MI8;
935 }
936 return is_high_op ? kX86Adc32RI8 : kX86Add32RI8;
937 }
938 if (in_mem) {
939 return is_high_op ? kX86Adc32MI : kX86Add32MI;
940 }
941 return is_high_op ? kX86Adc32RI : kX86Add32RI;
942 case Instruction::SUB_LONG:
943 case Instruction::SUB_LONG_2ADDR:
944 if (byte_imm) {
945 if (in_mem) {
946 return is_high_op ? kX86Sbb32MI8 : kX86Sub32MI8;
947 }
948 return is_high_op ? kX86Sbb32RI8 : kX86Sub32RI8;
949 }
950 if (in_mem) {
951 return is_high_op ? kX86Sbb32MI : kX86Sub32MI;
952 }
953 return is_high_op ? kX86Sbb32RI : kX86Sub32RI;
954 case Instruction::AND_LONG_2ADDR:
955 case Instruction::AND_LONG:
956 if (byte_imm) {
957 return in_mem ? kX86And32MI8 : kX86And32RI8;
958 }
959 return in_mem ? kX86And32MI : kX86And32RI;
960 case Instruction::OR_LONG:
961 case Instruction::OR_LONG_2ADDR:
962 if (byte_imm) {
963 return in_mem ? kX86Or32MI8 : kX86Or32RI8;
964 }
965 return in_mem ? kX86Or32MI : kX86Or32RI;
966 case Instruction::XOR_LONG:
967 case Instruction::XOR_LONG_2ADDR:
968 if (byte_imm) {
969 return in_mem ? kX86Xor32MI8 : kX86Xor32RI8;
970 }
971 return in_mem ? kX86Xor32MI : kX86Xor32RI;
972 default:
973 LOG(FATAL) << "Unexpected opcode: " << op;
974 return kX86Add32MI;
975 }
976}
977
978void X86Mir2Lir::GenLongImm(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op) {
979 DCHECK(rl_src.is_const);
980 int64_t val = mir_graph_->ConstantValueWide(rl_src);
981 int32_t val_lo = Low32Bits(val);
982 int32_t val_hi = High32Bits(val);
983 rl_dest = UpdateLocWide(rl_dest);
984
985 // Can we just do this into memory?
986 if ((rl_dest.location == kLocDalvikFrame) ||
987 (rl_dest.location == kLocCompilerTemp)) {
988 int rBase = TargetReg(kSp);
989 int displacement = SRegOffset(rl_dest.s_reg_low);
990
991 if (!IsNoOp(op, val_lo)) {
992 X86OpCode x86op = GetOpcode(op, rl_dest, false, val_lo);
993 LIR *lir = NewLIR3(x86op, rBase, displacement + LOWORD_OFFSET, val_lo);
994 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
995 false /* is_load */, true /* is64bit */);
996 }
997 if (!IsNoOp(op, val_hi)) {
998 X86OpCode x86op = GetOpcode(op, rl_dest, true, val_hi);
999 LIR *lir = NewLIR3(x86op, rBase, displacement + HIWORD_OFFSET, val_hi);
1000 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
1001 false /* is_load */, true /* is64bit */);
1002 }
1003 return;
1004 }
1005
1006 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
1007 DCHECK_EQ(rl_result.location, kLocPhysReg);
1008 DCHECK(!IsFpReg(rl_result.low_reg));
1009
1010 if (!IsNoOp(op, val_lo)) {
1011 X86OpCode x86op = GetOpcode(op, rl_result, false, val_lo);
1012 NewLIR2(x86op, rl_result.low_reg, val_lo);
1013 }
1014 if (!IsNoOp(op, val_hi)) {
1015 X86OpCode x86op = GetOpcode(op, rl_result, true, val_hi);
1016 NewLIR2(x86op, rl_result.high_reg, val_hi);
1017 }
1018 StoreValueWide(rl_dest, rl_result);
1019}
1020
1021void X86Mir2Lir::GenLongLongImm(RegLocation rl_dest, RegLocation rl_src1,
1022 RegLocation rl_src2, Instruction::Code op) {
1023 DCHECK(rl_src2.is_const);
1024 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
1025 int32_t val_lo = Low32Bits(val);
1026 int32_t val_hi = High32Bits(val);
1027 rl_dest = UpdateLocWide(rl_dest);
1028 rl_src1 = UpdateLocWide(rl_src1);
1029
1030 // Can we do this directly into the destination registers?
1031 if (rl_dest.location == kLocPhysReg && rl_src1.location == kLocPhysReg &&
1032 rl_dest.low_reg == rl_src1.low_reg && rl_dest.high_reg == rl_src1.high_reg &&
1033 !IsFpReg(rl_dest.low_reg)) {
1034 if (!IsNoOp(op, val_lo)) {
1035 X86OpCode x86op = GetOpcode(op, rl_dest, false, val_lo);
1036 NewLIR2(x86op, rl_dest.low_reg, val_lo);
1037 }
1038 if (!IsNoOp(op, val_hi)) {
1039 X86OpCode x86op = GetOpcode(op, rl_dest, true, val_hi);
1040 NewLIR2(x86op, rl_dest.high_reg, val_hi);
1041 }
1042 return;
1043 }
1044
1045 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
1046 DCHECK_EQ(rl_src1.location, kLocPhysReg);
1047
1048 // We need the values to be in a temporary
1049 RegLocation rl_result = ForceTempWide(rl_src1);
1050 if (!IsNoOp(op, val_lo)) {
1051 X86OpCode x86op = GetOpcode(op, rl_result, false, val_lo);
1052 NewLIR2(x86op, rl_result.low_reg, val_lo);
1053 }
1054 if (!IsNoOp(op, val_hi)) {
1055 X86OpCode x86op = GetOpcode(op, rl_result, true, val_hi);
1056 NewLIR2(x86op, rl_result.high_reg, val_hi);
1057 }
1058
1059 StoreFinalValueWide(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001060}
1061
1062} // namespace art