blob: ba9c611e9b92cf648459542e1034cc5fa624ebb4 [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"
buzbeeb5860fb2014-06-21 15:31:01 -070021#include "dex/reg_storage_eq.h"
Mingyao Yang98d1cc82014-05-15 17:02:16 -070022#include "mirror/art_method.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070023#include "mirror/array-inl.h"
Andreas Gampe7e499922015-01-06 08:28:12 -080024#include "utils.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070025#include "x86_lir.h"
26
27namespace art {
28
29/*
Brian Carlstrom7940e442013-07-12 13:46:57 -070030 * Compare two 64-bit values
31 * x = y return 0
32 * x < y return -1
33 * x > y return 1
34 */
35void X86Mir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070036 RegLocation rl_src2) {
Elena Sayapinadd644502014-07-01 18:39:52 +070037 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -070038 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
39 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
40 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Chao-ying Fua0147762014-06-06 18:38:49 -070041 RegStorage temp_reg = AllocTemp();
Serguei Katkov1c557032014-06-23 13:23:38 +070042 OpRegReg(kOpCmp, rl_src1.reg, rl_src2.reg);
43 NewLIR2(kX86Set8R, rl_result.reg.GetReg(), kX86CondG); // result = (src1 > src2) ? 1 : 0
44 NewLIR2(kX86Set8R, temp_reg.GetReg(), kX86CondL); // temp = (src1 >= src2) ? 0 : 1
45 NewLIR2(kX86Sub8RR, rl_result.reg.GetReg(), temp_reg.GetReg());
46 NewLIR2(kX86Movsx8qRR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
Serguei Katkov04982232014-06-20 18:17:16 +070047
Chao-ying Fua0147762014-06-06 18:38:49 -070048 StoreValue(rl_dest, rl_result);
49 FreeTemp(temp_reg);
50 return;
51 }
52
Maxim Kazantsev6dccdc22014-08-18 18:43:55 +070053 // Prepare for explicit register usage
54 ExplicitTempRegisterLock(this, 4, &rs_r0, &rs_r1, &rs_r2, &rs_r3);
buzbee091cc402014-03-31 10:14:40 -070055 RegStorage r_tmp1 = RegStorage::MakeRegPair(rs_r0, rs_r1);
56 RegStorage r_tmp2 = RegStorage::MakeRegPair(rs_r2, rs_r3);
buzbee2700f7e2014-03-07 09:46:20 -080057 LoadValueDirectWideFixed(rl_src1, r_tmp1);
58 LoadValueDirectWideFixed(rl_src2, r_tmp2);
Brian Carlstrom7940e442013-07-12 13:46:57 -070059 // Compute (r1:r0) = (r1:r0) - (r3:r2)
buzbee2700f7e2014-03-07 09:46:20 -080060 OpRegReg(kOpSub, rs_r0, rs_r2); // r0 = r0 - r2
61 OpRegReg(kOpSbc, rs_r1, rs_r3); // r1 = r1 - r3 - CF
buzbee091cc402014-03-31 10:14:40 -070062 NewLIR2(kX86Set8R, rs_r2.GetReg(), kX86CondL); // r2 = (r1:r0) < (r3:r2) ? 1 : 0
63 NewLIR2(kX86Movzx8RR, rs_r2.GetReg(), rs_r2.GetReg());
buzbee2700f7e2014-03-07 09:46:20 -080064 OpReg(kOpNeg, rs_r2); // r2 = -r2
65 OpRegReg(kOpOr, rs_r0, rs_r1); // r0 = high | low - sets ZF
buzbee091cc402014-03-31 10:14:40 -070066 NewLIR2(kX86Set8R, rs_r0.GetReg(), kX86CondNz); // r0 = (r1:r0) != (r3:r2) ? 1 : 0
Brian Carlstrom7940e442013-07-12 13:46:57 -070067 NewLIR2(kX86Movzx8RR, r0, r0);
buzbee2700f7e2014-03-07 09:46:20 -080068 OpRegReg(kOpOr, rs_r0, rs_r2); // r0 = r0 | r2
Brian Carlstrom7940e442013-07-12 13:46:57 -070069 RegLocation rl_result = LocCReturn();
70 StoreValue(rl_dest, rl_result);
71}
72
73X86ConditionCode X86ConditionEncoding(ConditionCode cond) {
74 switch (cond) {
75 case kCondEq: return kX86CondEq;
76 case kCondNe: return kX86CondNe;
77 case kCondCs: return kX86CondC;
78 case kCondCc: return kX86CondNc;
Vladimir Marko58af1f92013-12-19 13:31:15 +000079 case kCondUlt: return kX86CondC;
80 case kCondUge: return kX86CondNc;
Brian Carlstrom7940e442013-07-12 13:46:57 -070081 case kCondMi: return kX86CondS;
82 case kCondPl: return kX86CondNs;
83 case kCondVs: return kX86CondO;
84 case kCondVc: return kX86CondNo;
85 case kCondHi: return kX86CondA;
86 case kCondLs: return kX86CondBe;
87 case kCondGe: return kX86CondGe;
88 case kCondLt: return kX86CondL;
89 case kCondGt: return kX86CondG;
90 case kCondLe: return kX86CondLe;
91 case kCondAl:
92 case kCondNv: LOG(FATAL) << "Should not reach here";
93 }
94 return kX86CondO;
95}
96
buzbee2700f7e2014-03-07 09:46:20 -080097LIR* X86Mir2Lir::OpCmpBranch(ConditionCode cond, RegStorage src1, RegStorage src2, LIR* target) {
Chao-ying Fua77ee512014-07-01 17:43:41 -070098 NewLIR2(src1.Is64Bit() ? kX86Cmp64RR : kX86Cmp32RR, src1.GetReg(), src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070099 X86ConditionCode cc = X86ConditionEncoding(cond);
100 LIR* branch = NewLIR2(kX86Jcc8, 0 /* lir operand for Jcc offset */ ,
101 cc);
102 branch->target = target;
103 return branch;
104}
105
buzbee2700f7e2014-03-07 09:46:20 -0800106LIR* X86Mir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700107 int check_value, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700108 if ((check_value == 0) && (cond == kCondEq || cond == kCondNe)) {
109 // TODO: when check_value == 0 and reg is rCX, use the jcxz/nz opcode
Chao-ying Fua77ee512014-07-01 17:43:41 -0700110 NewLIR2(reg.Is64Bit() ? kX86Test64RR: kX86Test32RR, reg.GetReg(), reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700111 } else {
Chao-ying Fua77ee512014-07-01 17:43:41 -0700112 if (reg.Is64Bit()) {
113 NewLIR2(IS_SIMM8(check_value) ? kX86Cmp64RI8 : kX86Cmp64RI, reg.GetReg(), check_value);
114 } else {
115 NewLIR2(IS_SIMM8(check_value) ? kX86Cmp32RI8 : kX86Cmp32RI, reg.GetReg(), check_value);
116 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700117 }
118 X86ConditionCode cc = X86ConditionEncoding(cond);
119 LIR* branch = NewLIR2(kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc);
120 branch->target = target;
121 return branch;
122}
123
buzbee2700f7e2014-03-07 09:46:20 -0800124LIR* X86Mir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) {
125 // If src or dest is a pair, we'll be using low reg.
126 if (r_dest.IsPair()) {
127 r_dest = r_dest.GetLow();
128 }
129 if (r_src.IsPair()) {
130 r_src = r_src.GetLow();
131 }
buzbee091cc402014-03-31 10:14:40 -0700132 if (r_dest.IsFloat() || r_src.IsFloat())
Brian Carlstrom7940e442013-07-12 13:46:57 -0700133 return OpFpRegCopy(r_dest, r_src);
Chao-ying Fue0ccdc02014-06-06 17:32:37 -0700134 LIR* res = RawLIR(current_dalvik_offset_, r_dest.Is64Bit() ? kX86Mov64RR : kX86Mov32RR,
buzbee2700f7e2014-03-07 09:46:20 -0800135 r_dest.GetReg(), r_src.GetReg());
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800136 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700137 res->flags.is_nop = true;
138 }
139 return res;
140}
141
buzbee7a11ab02014-04-28 20:02:38 -0700142void X86Mir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
143 if (r_dest != r_src) {
144 LIR *res = OpRegCopyNoInsert(r_dest, r_src);
145 AppendLIR(res);
146 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700147}
148
buzbee2700f7e2014-03-07 09:46:20 -0800149void X86Mir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
buzbee7a11ab02014-04-28 20:02:38 -0700150 if (r_dest != r_src) {
buzbee091cc402014-03-31 10:14:40 -0700151 bool dest_fp = r_dest.IsFloat();
152 bool src_fp = r_src.IsFloat();
buzbee7a11ab02014-04-28 20:02:38 -0700153 if (dest_fp) {
154 if (src_fp) {
buzbee091cc402014-03-31 10:14:40 -0700155 OpRegCopy(r_dest, r_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700156 } else {
buzbee7a11ab02014-04-28 20:02:38 -0700157 // TODO: Prevent this from happening in the code. The result is often
158 // unused or could have been loaded more easily from memory.
Chao-ying Fue0ccdc02014-06-06 17:32:37 -0700159 if (!r_src.IsPair()) {
160 DCHECK(!r_dest.IsPair());
161 NewLIR2(kX86MovqxrRR, r_dest.GetReg(), r_src.GetReg());
162 } else {
163 NewLIR2(kX86MovdxrRR, r_dest.GetReg(), r_src.GetLowReg());
164 RegStorage r_tmp = AllocTempDouble();
165 NewLIR2(kX86MovdxrRR, r_tmp.GetReg(), r_src.GetHighReg());
166 NewLIR2(kX86PunpckldqRR, r_dest.GetReg(), r_tmp.GetReg());
167 FreeTemp(r_tmp);
168 }
buzbee7a11ab02014-04-28 20:02:38 -0700169 }
170 } else {
171 if (src_fp) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -0700172 if (!r_dest.IsPair()) {
173 DCHECK(!r_src.IsPair());
174 NewLIR2(kX86MovqrxRR, r_dest.GetReg(), r_src.GetReg());
buzbee7a11ab02014-04-28 20:02:38 -0700175 } else {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -0700176 NewLIR2(kX86MovdrxRR, r_dest.GetLowReg(), r_src.GetReg());
177 RegStorage temp_reg = AllocTempDouble();
178 NewLIR2(kX86MovsdRR, temp_reg.GetReg(), r_src.GetReg());
179 NewLIR2(kX86PsrlqRI, temp_reg.GetReg(), 32);
180 NewLIR2(kX86MovdrxRR, r_dest.GetHighReg(), temp_reg.GetReg());
181 }
182 } else {
183 DCHECK_EQ(r_dest.IsPair(), r_src.IsPair());
184 if (!r_src.IsPair()) {
185 // Just copy the register directly.
186 OpRegCopy(r_dest, r_src);
187 } else {
188 // Handle overlap
189 if (r_src.GetHighReg() == r_dest.GetLowReg() &&
190 r_src.GetLowReg() == r_dest.GetHighReg()) {
191 // Deal with cycles.
192 RegStorage temp_reg = AllocTemp();
193 OpRegCopy(temp_reg, r_dest.GetHigh());
194 OpRegCopy(r_dest.GetHigh(), r_dest.GetLow());
195 OpRegCopy(r_dest.GetLow(), temp_reg);
196 FreeTemp(temp_reg);
197 } else if (r_src.GetHighReg() == r_dest.GetLowReg()) {
198 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
199 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
200 } else {
201 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
202 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
203 }
buzbee7a11ab02014-04-28 20:02:38 -0700204 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700205 }
206 }
207 }
208}
209
Andreas Gampe90969af2014-07-15 23:02:11 -0700210void X86Mir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
211 int32_t true_val, int32_t false_val, RegStorage rs_dest,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700212 RegisterClass dest_reg_class) {
Serguei Katkov9ee45192014-07-17 14:39:03 +0700213 DCHECK(!left_op.IsPair() && !right_op.IsPair() && !rs_dest.IsPair());
214 DCHECK(!left_op.IsFloat() && !right_op.IsFloat() && !rs_dest.IsFloat());
215
216 // We really need this check for correctness, otherwise we will need to do more checks in
217 // non zero/one case
218 if (true_val == false_val) {
219 LoadConstantNoClobber(rs_dest, true_val);
220 return;
Andreas Gampe90969af2014-07-15 23:02:11 -0700221 }
222
Serguei Katkov9ee45192014-07-17 14:39:03 +0700223 const bool dest_intersect = IsSameReg(rs_dest, left_op) || IsSameReg(rs_dest, right_op);
224
225 const bool zero_one_case = (true_val == 0 && false_val == 1) || (true_val == 1 && false_val == 0);
226 if (zero_one_case && IsByteRegister(rs_dest)) {
227 if (!dest_intersect) {
228 LoadConstantNoClobber(rs_dest, 0);
229 }
230 OpRegReg(kOpCmp, left_op, right_op);
231 // Set the low byte of the result to 0 or 1 from the compare condition code.
232 NewLIR2(kX86Set8R, rs_dest.GetReg(),
233 X86ConditionEncoding(true_val == 1 ? code : FlipComparisonOrder(code)));
234 if (dest_intersect) {
235 NewLIR2(rs_dest.Is64Bit() ? kX86Movzx8qRR : kX86Movzx8RR, rs_dest.GetReg(), rs_dest.GetReg());
236 }
237 } else {
238 // Be careful rs_dest can be changed only after cmp because it can be the same as one of ops
239 // and it cannot use xor because it makes cc flags to be dirty
240 RegStorage temp_reg = AllocTypedTemp(false, dest_reg_class, false);
241 if (temp_reg.Valid()) {
242 if (false_val == 0 && dest_intersect) {
243 code = FlipComparisonOrder(code);
244 std::swap(true_val, false_val);
245 }
246 if (!dest_intersect) {
247 LoadConstantNoClobber(rs_dest, false_val);
248 }
249 LoadConstantNoClobber(temp_reg, true_val);
250 OpRegReg(kOpCmp, left_op, right_op);
251 if (dest_intersect) {
252 LoadConstantNoClobber(rs_dest, false_val);
253 DCHECK(!last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode));
254 }
255 OpCondRegReg(kOpCmov, code, rs_dest, temp_reg);
256 FreeTemp(temp_reg);
257 } else {
258 // slow path
259 LIR* cmp_branch = OpCmpBranch(code, left_op, right_op, nullptr);
260 LoadConstantNoClobber(rs_dest, false_val);
261 LIR* that_is_it = NewLIR1(kX86Jmp8, 0);
262 LIR* true_case = NewLIR0(kPseudoTargetLabel);
263 cmp_branch->target = true_case;
264 LoadConstantNoClobber(rs_dest, true_val);
265 LIR* end = NewLIR0(kPseudoTargetLabel);
266 that_is_it->target = end;
267 }
268 }
Andreas Gampe90969af2014-07-15 23:02:11 -0700269}
270
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700271void X86Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700272 UNUSED(bb);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800273 RegLocation rl_result;
274 RegLocation rl_src = mir_graph_->GetSrc(mir, 0);
275 RegLocation rl_dest = mir_graph_->GetDest(mir);
buzbeea0cd2d72014-06-01 09:33:49 -0700276 // Avoid using float regs here.
277 RegisterClass src_reg_class = rl_src.ref ? kRefReg : kCoreReg;
278 RegisterClass result_reg_class = rl_dest.ref ? kRefReg : kCoreReg;
Vladimir Markoa1a70742014-03-03 10:28:05 +0000279 ConditionCode ccode = mir->meta.ccode;
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800280
281 // The kMirOpSelect has two variants, one for constants and one for moves.
282 const bool is_constant_case = (mir->ssa_rep->num_uses == 1);
283
284 if (is_constant_case) {
285 int true_val = mir->dalvikInsn.vB;
286 int false_val = mir->dalvikInsn.vC;
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800287
Jean Christophe Beyler3f51e7d2014-09-04 08:34:28 -0700288 // simplest strange case
289 if (true_val == false_val) {
290 rl_result = EvalLoc(rl_dest, result_reg_class, true);
291 LoadConstantNoClobber(rl_result.reg, true_val);
292 } else {
293 // TODO: use GenSelectConst32 and handle additional opcode patterns such as
294 // "cmp; setcc; movzx" or "cmp; sbb r0,r0; and r0,$mask; add r0,$literal".
295 rl_src = LoadValue(rl_src, src_reg_class);
296 rl_result = EvalLoc(rl_dest, result_reg_class, true);
297 /*
298 * For ccode == kCondEq:
299 *
300 * 1) When the true case is zero and result_reg is not same as src_reg:
301 * xor result_reg, result_reg
302 * cmp $0, src_reg
303 * mov t1, $false_case
304 * cmovnz result_reg, t1
305 * 2) When the false case is zero and result_reg is not same as src_reg:
306 * xor result_reg, result_reg
307 * cmp $0, src_reg
308 * mov t1, $true_case
309 * cmovz result_reg, t1
310 * 3) All other cases (we do compare first to set eflags):
311 * cmp $0, src_reg
312 * mov result_reg, $false_case
313 * mov t1, $true_case
314 * cmovz result_reg, t1
315 */
316 // FIXME: depending on how you use registers you could get a false != mismatch when dealing
317 // with different views of the same underlying physical resource (i.e. solo32 vs. solo64).
318 const bool result_reg_same_as_src =
319 (rl_src.location == kLocPhysReg && rl_src.reg.GetRegNum() == rl_result.reg.GetRegNum());
320 const bool true_zero_case = (true_val == 0 && false_val != 0 && !result_reg_same_as_src);
321 const bool false_zero_case = (false_val == 0 && true_val != 0 && !result_reg_same_as_src);
322 const bool catch_all_case = !(true_zero_case || false_zero_case);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800323
Jean Christophe Beyler3f51e7d2014-09-04 08:34:28 -0700324 if (true_zero_case || false_zero_case) {
325 OpRegReg(kOpXor, rl_result.reg, rl_result.reg);
326 }
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800327
Jean Christophe Beyler3f51e7d2014-09-04 08:34:28 -0700328 if (true_zero_case || false_zero_case || catch_all_case) {
329 OpRegImm(kOpCmp, rl_src.reg, 0);
330 }
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800331
Jean Christophe Beyler3f51e7d2014-09-04 08:34:28 -0700332 if (catch_all_case) {
333 OpRegImm(kOpMov, rl_result.reg, false_val);
334 }
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800335
Jean Christophe Beyler3f51e7d2014-09-04 08:34:28 -0700336 if (true_zero_case || false_zero_case || catch_all_case) {
337 ConditionCode cc = true_zero_case ? NegateComparison(ccode) : ccode;
338 int immediateForTemp = true_zero_case ? false_val : true_val;
339 RegStorage temp1_reg = AllocTypedTemp(false, result_reg_class);
340 OpRegImm(kOpMov, temp1_reg, immediateForTemp);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800341
Jean Christophe Beyler3f51e7d2014-09-04 08:34:28 -0700342 OpCondRegReg(kOpCmov, cc, rl_result.reg, temp1_reg);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800343
Jean Christophe Beyler3f51e7d2014-09-04 08:34:28 -0700344 FreeTemp(temp1_reg);
345 }
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800346 }
347 } else {
Jean Christophe Beyler3f51e7d2014-09-04 08:34:28 -0700348 rl_src = LoadValue(rl_src, src_reg_class);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800349 RegLocation rl_true = mir_graph_->GetSrc(mir, 1);
350 RegLocation rl_false = mir_graph_->GetSrc(mir, 2);
buzbeea0cd2d72014-06-01 09:33:49 -0700351 rl_true = LoadValue(rl_true, result_reg_class);
352 rl_false = LoadValue(rl_false, result_reg_class);
353 rl_result = EvalLoc(rl_dest, result_reg_class, true);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800354
355 /*
Vladimir Markoa1a70742014-03-03 10:28:05 +0000356 * For ccode == kCondEq:
357 *
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800358 * 1) When true case is already in place:
359 * cmp $0, src_reg
360 * cmovnz result_reg, false_reg
361 * 2) When false case is already in place:
362 * cmp $0, src_reg
363 * cmovz result_reg, true_reg
364 * 3) When neither cases are in place:
365 * cmp $0, src_reg
Vladimir Markoa1a70742014-03-03 10:28:05 +0000366 * mov result_reg, false_reg
367 * cmovz result_reg, true_reg
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800368 */
369
370 // kMirOpSelect is generated just for conditional cases when comparison is done with zero.
buzbee2700f7e2014-03-07 09:46:20 -0800371 OpRegImm(kOpCmp, rl_src.reg, 0);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800372
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000373 if (rl_result.reg.GetReg() == rl_true.reg.GetReg()) {
buzbee2700f7e2014-03-07 09:46:20 -0800374 OpCondRegReg(kOpCmov, NegateComparison(ccode), rl_result.reg, rl_false.reg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000375 } else if (rl_result.reg.GetReg() == rl_false.reg.GetReg()) {
buzbee2700f7e2014-03-07 09:46:20 -0800376 OpCondRegReg(kOpCmov, ccode, rl_result.reg, rl_true.reg);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800377 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800378 OpRegCopy(rl_result.reg, rl_false.reg);
379 OpCondRegReg(kOpCmov, ccode, rl_result.reg, rl_true.reg);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800380 }
381 }
382
383 StoreValue(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700384}
385
386void X86Mir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
buzbee0d829482013-10-11 15:24:55 -0700387 LIR* taken = &block_label_list_[bb->taken];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700388 RegLocation rl_src1 = mir_graph_->GetSrcWide(mir, 0);
389 RegLocation rl_src2 = mir_graph_->GetSrcWide(mir, 2);
Vladimir Markoa8946072014-01-22 10:30:44 +0000390 ConditionCode ccode = mir->meta.ccode;
Mark Mendell412d4f82013-12-18 13:32:36 -0800391
392 if (rl_src1.is_const) {
393 std::swap(rl_src1, rl_src2);
394 ccode = FlipComparisonOrder(ccode);
395 }
396 if (rl_src2.is_const) {
397 // Do special compare/branch against simple const operand
398 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
399 GenFusedLongCmpImmBranch(bb, rl_src1, val, ccode);
400 return;
401 }
402
Elena Sayapinadd644502014-07-01 18:39:52 +0700403 if (cu_->target64) {
Dmitry Petrochenko3157f9a2014-06-18 19:11:41 +0700404 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
405 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
406
407 OpRegReg(kOpCmp, rl_src1.reg, rl_src2.reg);
408 OpCondBranch(ccode, taken);
409 return;
410 }
411
Maxim Kazantsev6dccdc22014-08-18 18:43:55 +0700412 // Prepare for explicit register usage
413 ExplicitTempRegisterLock(this, 4, &rs_r0, &rs_r1, &rs_r2, &rs_r3);
buzbee091cc402014-03-31 10:14:40 -0700414 RegStorage r_tmp1 = RegStorage::MakeRegPair(rs_r0, rs_r1);
415 RegStorage r_tmp2 = RegStorage::MakeRegPair(rs_r2, rs_r3);
buzbee2700f7e2014-03-07 09:46:20 -0800416 LoadValueDirectWideFixed(rl_src1, r_tmp1);
417 LoadValueDirectWideFixed(rl_src2, r_tmp2);
Dmitry Petrochenko3157f9a2014-06-18 19:11:41 +0700418
Brian Carlstrom7940e442013-07-12 13:46:57 -0700419 // Swap operands and condition code to prevent use of zero flag.
420 if (ccode == kCondLe || ccode == kCondGt) {
421 // Compute (r3:r2) = (r3:r2) - (r1:r0)
buzbee2700f7e2014-03-07 09:46:20 -0800422 OpRegReg(kOpSub, rs_r2, rs_r0); // r2 = r2 - r0
423 OpRegReg(kOpSbc, rs_r3, rs_r1); // r3 = r3 - r1 - CF
Brian Carlstrom7940e442013-07-12 13:46:57 -0700424 } else {
425 // Compute (r1:r0) = (r1:r0) - (r3:r2)
buzbee2700f7e2014-03-07 09:46:20 -0800426 OpRegReg(kOpSub, rs_r0, rs_r2); // r0 = r0 - r2
427 OpRegReg(kOpSbc, rs_r1, rs_r3); // r1 = r1 - r3 - CF
Brian Carlstrom7940e442013-07-12 13:46:57 -0700428 }
429 switch (ccode) {
430 case kCondEq:
431 case kCondNe:
buzbee2700f7e2014-03-07 09:46:20 -0800432 OpRegReg(kOpOr, rs_r0, rs_r1); // r0 = r0 | r1
Brian Carlstrom7940e442013-07-12 13:46:57 -0700433 break;
434 case kCondLe:
435 ccode = kCondGe;
436 break;
437 case kCondGt:
438 ccode = kCondLt;
439 break;
440 case kCondLt:
441 case kCondGe:
442 break;
443 default:
444 LOG(FATAL) << "Unexpected ccode: " << ccode;
445 }
446 OpCondBranch(ccode, taken);
447}
448
Mark Mendell412d4f82013-12-18 13:32:36 -0800449void X86Mir2Lir::GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1,
450 int64_t val, ConditionCode ccode) {
451 int32_t val_lo = Low32Bits(val);
452 int32_t val_hi = High32Bits(val);
453 LIR* taken = &block_label_list_[bb->taken];
Mark Mendell412d4f82013-12-18 13:32:36 -0800454 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
Mark Mendell752e2052014-05-01 10:19:04 -0400455 bool is_equality_test = ccode == kCondEq || ccode == kCondNe;
Dmitry Petrochenko3157f9a2014-06-18 19:11:41 +0700456
Elena Sayapinadd644502014-07-01 18:39:52 +0700457 if (cu_->target64) {
Dmitry Petrochenko3157f9a2014-06-18 19:11:41 +0700458 if (is_equality_test && val == 0) {
459 // We can simplify of comparing for ==, != to 0.
460 NewLIR2(kX86Test64RR, rl_src1.reg.GetReg(), rl_src1.reg.GetReg());
461 } else if (is_equality_test && val_hi == 0 && val_lo > 0) {
462 OpRegImm(kOpCmp, rl_src1.reg, val_lo);
463 } else {
464 RegStorage tmp = AllocTypedTempWide(false, kCoreReg);
465 LoadConstantWide(tmp, val);
466 OpRegReg(kOpCmp, rl_src1.reg, tmp);
467 FreeTemp(tmp);
468 }
469 OpCondBranch(ccode, taken);
470 return;
471 }
472
Mark Mendell752e2052014-05-01 10:19:04 -0400473 if (is_equality_test && val != 0) {
474 rl_src1 = ForceTempWide(rl_src1);
475 }
buzbee2700f7e2014-03-07 09:46:20 -0800476 RegStorage low_reg = rl_src1.reg.GetLow();
477 RegStorage high_reg = rl_src1.reg.GetHigh();
Mark Mendell412d4f82013-12-18 13:32:36 -0800478
Mark Mendell752e2052014-05-01 10:19:04 -0400479 if (is_equality_test) {
Dmitry Petrochenko3157f9a2014-06-18 19:11:41 +0700480 // We can simplify of comparing for ==, != to 0.
Mark Mendell752e2052014-05-01 10:19:04 -0400481 if (val == 0) {
482 if (IsTemp(low_reg)) {
483 OpRegReg(kOpOr, low_reg, high_reg);
484 // We have now changed it; ignore the old values.
485 Clobber(rl_src1.reg);
486 } else {
487 RegStorage t_reg = AllocTemp();
488 OpRegRegReg(kOpOr, t_reg, low_reg, high_reg);
489 FreeTemp(t_reg);
490 }
491 OpCondBranch(ccode, taken);
492 return;
493 }
494
495 // Need to compute the actual value for ==, !=.
496 OpRegImm(kOpSub, low_reg, val_lo);
497 NewLIR2(kX86Sbb32RI, high_reg.GetReg(), val_hi);
498 OpRegReg(kOpOr, high_reg, low_reg);
499 Clobber(rl_src1.reg);
500 } else if (ccode == kCondLe || ccode == kCondGt) {
501 // Swap operands and condition code to prevent use of zero flag.
502 RegStorage tmp = AllocTypedTempWide(false, kCoreReg);
503 LoadConstantWide(tmp, val);
504 OpRegReg(kOpSub, tmp.GetLow(), low_reg);
505 OpRegReg(kOpSbc, tmp.GetHigh(), high_reg);
506 ccode = (ccode == kCondLe) ? kCondGe : kCondLt;
507 FreeTemp(tmp);
508 } else {
509 // We can use a compare for the low word to set CF.
510 OpRegImm(kOpCmp, low_reg, val_lo);
511 if (IsTemp(high_reg)) {
512 NewLIR2(kX86Sbb32RI, high_reg.GetReg(), val_hi);
513 // We have now changed it; ignore the old values.
514 Clobber(rl_src1.reg);
515 } else {
516 // mov temp_reg, high_reg; sbb temp_reg, high_constant
517 RegStorage t_reg = AllocTemp();
518 OpRegCopy(t_reg, high_reg);
519 NewLIR2(kX86Sbb32RI, t_reg.GetReg(), val_hi);
520 FreeTemp(t_reg);
521 }
Mark Mendell412d4f82013-12-18 13:32:36 -0800522 }
523
Mark Mendell752e2052014-05-01 10:19:04 -0400524 OpCondBranch(ccode, taken);
Mark Mendell412d4f82013-12-18 13:32:36 -0800525}
526
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700527void X86Mir2Lir::CalculateMagicAndShift(int64_t divisor, int64_t& magic, int& shift, bool is_long) {
Mark Mendell2bf31e62014-01-23 12:13:40 -0800528 // It does not make sense to calculate magic and shift for zero divisor.
529 DCHECK_NE(divisor, 0);
530
531 /* According to H.S.Warren's Hacker's Delight Chapter 10 and
532 * T,Grablund, P.L.Montogomery's Division by invariant integers using multiplication.
533 * The magic number M and shift S can be calculated in the following way:
534 * Let nc be the most positive value of numerator(n) such that nc = kd - 1,
535 * where divisor(d) >=2.
536 * Let nc be the most negative value of numerator(n) such that nc = kd + 1,
537 * where divisor(d) <= -2.
538 * Thus nc can be calculated like:
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700539 * nc = exp + exp % d - 1, where d >= 2 and exp = 2^31 for int or 2^63 for long
540 * nc = -exp + (exp + 1) % d, where d >= 2 and exp = 2^31 for int or 2^63 for long
Mark Mendell2bf31e62014-01-23 12:13:40 -0800541 *
542 * So the shift p is the smallest p satisfying
543 * 2^p > nc * (d - 2^p % d), where d >= 2
544 * 2^p > nc * (d + 2^p % d), where d <= -2.
545 *
546 * the magic number M is calcuated by
547 * M = (2^p + d - 2^p % d) / d, where d >= 2
548 * M = (2^p - d - 2^p % d) / d, where d <= -2.
549 *
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700550 * Notice that p is always bigger than or equal to 32/64, so we just return 32-p/64-p as
Mark Mendell2bf31e62014-01-23 12:13:40 -0800551 * the shift number S.
552 */
553
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700554 int64_t p = (is_long) ? 63 : 31;
555 const uint64_t exp = (is_long) ? 0x8000000000000000ULL : 0x80000000U;
Mark Mendell2bf31e62014-01-23 12:13:40 -0800556
557 // Initialize the computations.
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700558 uint64_t abs_d = (divisor >= 0) ? divisor : -divisor;
559 uint64_t tmp = exp + ((is_long) ? static_cast<uint64_t>(divisor) >> 63 :
560 static_cast<uint32_t>(divisor) >> 31);
561 uint64_t abs_nc = tmp - 1 - tmp % abs_d;
562 uint64_t quotient1 = exp / abs_nc;
563 uint64_t remainder1 = exp % abs_nc;
564 uint64_t quotient2 = exp / abs_d;
565 uint64_t remainder2 = exp % abs_d;
Mark Mendell2bf31e62014-01-23 12:13:40 -0800566
567 /*
568 * To avoid handling both positive and negative divisor, Hacker's Delight
569 * introduces a method to handle these 2 cases together to avoid duplication.
570 */
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700571 uint64_t delta;
Mark Mendell2bf31e62014-01-23 12:13:40 -0800572 do {
573 p++;
574 quotient1 = 2 * quotient1;
575 remainder1 = 2 * remainder1;
576 if (remainder1 >= abs_nc) {
577 quotient1++;
578 remainder1 = remainder1 - abs_nc;
579 }
580 quotient2 = 2 * quotient2;
581 remainder2 = 2 * remainder2;
582 if (remainder2 >= abs_d) {
583 quotient2++;
584 remainder2 = remainder2 - abs_d;
585 }
586 delta = abs_d - remainder2;
587 } while (quotient1 < delta || (quotient1 == delta && remainder1 == 0));
588
589 magic = (divisor > 0) ? (quotient2 + 1) : (-quotient2 - 1);
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700590
591 if (!is_long) {
592 magic = static_cast<int>(magic);
593 }
594
595 shift = (is_long) ? p - 64 : p - 32;
Mark Mendell2bf31e62014-01-23 12:13:40 -0800596}
597
buzbee2700f7e2014-03-07 09:46:20 -0800598RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg_lo, int lit, bool is_div) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700599 UNUSED(rl_dest, reg_lo, lit, is_div);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700600 LOG(FATAL) << "Unexpected use of GenDivRemLit for x86";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700601 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700602}
603
Mark Mendell2bf31e62014-01-23 12:13:40 -0800604RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src,
605 int imm, bool is_div) {
606 // Use a multiply (and fixup) to perform an int div/rem by a constant.
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700607 RegLocation rl_result;
Mark Mendell2bf31e62014-01-23 12:13:40 -0800608
Alexei Zavjalov79aa4232014-02-13 13:55:50 +0700609 if (imm == 1) {
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700610 rl_result = EvalLoc(rl_dest, kCoreReg, true);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800611 if (is_div) {
Alexei Zavjalov79aa4232014-02-13 13:55:50 +0700612 // x / 1 == x.
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700613 LoadValueDirectFixed(rl_src, rl_result.reg);
Alexei Zavjalov79aa4232014-02-13 13:55:50 +0700614 } else {
615 // x % 1 == 0.
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700616 LoadConstantNoClobber(rl_result.reg, 0);
Alexei Zavjalov79aa4232014-02-13 13:55:50 +0700617 }
618 } else if (imm == -1) { // handle 0x80000000 / -1 special case.
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700619 rl_result = EvalLoc(rl_dest, kCoreReg, true);
Alexei Zavjalov79aa4232014-02-13 13:55:50 +0700620 if (is_div) {
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700621 LoadValueDirectFixed(rl_src, rl_result.reg);
Yixin Shou2ddd1752014-08-26 15:15:13 -0400622
623 // Check if numerator is 0
624 OpRegImm(kOpCmp, rl_result.reg, 0);
625 LIR* branch = NewLIR2(kX86Jcc8, 0, kX86CondEq);
626
627 // handle 0x80000000 / -1
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700628 OpRegImm(kOpCmp, rl_result.reg, 0x80000000);
629 LIR *minint_branch = NewLIR2(kX86Jcc8, 0, kX86CondEq);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800630
631 // for x != MIN_INT, x / -1 == -x.
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700632 NewLIR1(kX86Neg32R, rl_result.reg.GetReg());
Mark Mendell2bf31e62014-01-23 12:13:40 -0800633
Mark Mendell2bf31e62014-01-23 12:13:40 -0800634 // EAX already contains the right value (0x80000000),
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700635 minint_branch->target = NewLIR0(kPseudoTargetLabel);
Yixin Shou2ddd1752014-08-26 15:15:13 -0400636 branch->target = NewLIR0(kPseudoTargetLabel);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800637 } else {
638 // x % -1 == 0.
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700639 LoadConstantNoClobber(rl_result.reg, 0);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800640 }
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700641 } else if (is_div && IsPowerOfTwo(std::abs(imm))) {
642 // Division using shifting.
643 rl_src = LoadValue(rl_src, kCoreReg);
644 rl_result = EvalLoc(rl_dest, kCoreReg, true);
645 if (IsSameReg(rl_result.reg, rl_src.reg)) {
646 RegStorage rs_temp = AllocTypedTemp(false, kCoreReg);
647 rl_result.reg.SetReg(rs_temp.GetReg());
648 }
Yixin Shou2ddd1752014-08-26 15:15:13 -0400649
650 // Check if numerator is 0
651 OpRegImm(kOpCmp, rl_src.reg, 0);
652 LIR* branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
653 LoadConstantNoClobber(rl_result.reg, 0);
654 LIR* done = NewLIR1(kX86Jmp8, 0);
655 branch->target = NewLIR0(kPseudoTargetLabel);
656
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700657 NewLIR3(kX86Lea32RM, rl_result.reg.GetReg(), rl_src.reg.GetReg(), std::abs(imm) - 1);
658 NewLIR2(kX86Test32RR, rl_src.reg.GetReg(), rl_src.reg.GetReg());
659 OpCondRegReg(kOpCmov, kCondPl, rl_result.reg, rl_src.reg);
Andreas Gampe7e499922015-01-06 08:28:12 -0800660 int shift_amount = CTZ(imm);
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700661 OpRegImm(kOpAsr, rl_result.reg, shift_amount);
662 if (imm < 0) {
663 OpReg(kOpNeg, rl_result.reg);
664 }
Yixin Shou2ddd1752014-08-26 15:15:13 -0400665 done->target = NewLIR0(kPseudoTargetLabel);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800666 } else {
Alexei Zavjalov79aa4232014-02-13 13:55:50 +0700667 CHECK(imm <= -2 || imm >= 2);
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700668
Mark Mendell2bf31e62014-01-23 12:13:40 -0800669 // Use H.S.Warren's Hacker's Delight Chapter 10 and
670 // T,Grablund, P.L.Montogomery's Division by invariant integers using multiplication.
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700671 int64_t magic;
672 int shift;
673 CalculateMagicAndShift((int64_t)imm, magic, shift, false /* is_long */);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800674
675 /*
676 * For imm >= 2,
677 * int(n/imm) = floor(n/imm) = floor(M*n/2^S), while n > 0
678 * int(n/imm) = ceil(n/imm) = floor(M*n/2^S) +1, while n < 0.
679 * For imm <= -2,
680 * int(n/imm) = ceil(n/imm) = floor(M*n/2^S) +1 , while n > 0
681 * int(n/imm) = floor(n/imm) = floor(M*n/2^S), while n < 0.
682 * We implement this algorithm in the following way:
683 * 1. multiply magic number m and numerator n, get the higher 32bit result in EDX
684 * 2. if imm > 0 and magic < 0, add numerator to EDX
685 * if imm < 0 and magic > 0, sub numerator from EDX
686 * 3. if S !=0, SAR S bits for EDX
687 * 4. add 1 to EDX if EDX < 0
688 * 5. Thus, EDX is the quotient
689 */
690
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700691 FlushReg(rs_r0);
692 Clobber(rs_r0);
693 LockTemp(rs_r0);
694 FlushReg(rs_r2);
695 Clobber(rs_r2);
696 LockTemp(rs_r2);
697
Mark Mendell3a91f442014-09-02 12:44:24 -0400698 // Assume that the result will be in EDX for divide, and EAX for remainder.
699 rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, is_div ? rs_r2 : rs_r0,
700 INVALID_SREG, INVALID_SREG};
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +0700701
Mark Mendell3a91f442014-09-02 12:44:24 -0400702 // We need the value at least twice. Load into a temp.
703 rl_src = LoadValue(rl_src, kCoreReg);
704 RegStorage numerator_reg = rl_src.reg;
Mark Mendell2bf31e62014-01-23 12:13:40 -0800705
Mark Mendell3a91f442014-09-02 12:44:24 -0400706 // Check if numerator is 0.
707 OpRegImm(kOpCmp, numerator_reg, 0);
Yixin Shou2ddd1752014-08-26 15:15:13 -0400708 LIR* branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
Mark Mendell3a91f442014-09-02 12:44:24 -0400709 // Return result 0 if numerator was 0.
710 LoadConstantNoClobber(rl_result.reg, 0);
Yixin Shou2ddd1752014-08-26 15:15:13 -0400711 LIR* done = NewLIR1(kX86Jmp8, 0);
712 branch->target = NewLIR0(kPseudoTargetLabel);
713
Mark Mendell3a91f442014-09-02 12:44:24 -0400714 // EAX = magic.
715 LoadConstant(rs_r0, magic);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800716
Mark Mendell3a91f442014-09-02 12:44:24 -0400717 // EDX:EAX = magic * numerator.
718 NewLIR1(kX86Imul32DaR, numerator_reg.GetReg());
Mark Mendell2bf31e62014-01-23 12:13:40 -0800719
720 if (imm > 0 && magic < 0) {
721 // Add numerator to EDX.
buzbee2700f7e2014-03-07 09:46:20 -0800722 DCHECK(numerator_reg.Valid());
buzbee091cc402014-03-31 10:14:40 -0700723 NewLIR2(kX86Add32RR, rs_r2.GetReg(), numerator_reg.GetReg());
Mark Mendell2bf31e62014-01-23 12:13:40 -0800724 } else if (imm < 0 && magic > 0) {
buzbee2700f7e2014-03-07 09:46:20 -0800725 DCHECK(numerator_reg.Valid());
buzbee091cc402014-03-31 10:14:40 -0700726 NewLIR2(kX86Sub32RR, rs_r2.GetReg(), numerator_reg.GetReg());
Mark Mendell2bf31e62014-01-23 12:13:40 -0800727 }
728
729 // Do we need the shift?
730 if (shift != 0) {
731 // Shift EDX by 'shift' bits.
buzbee091cc402014-03-31 10:14:40 -0700732 NewLIR2(kX86Sar32RI, rs_r2.GetReg(), shift);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800733 }
734
735 // Add 1 to EDX if EDX < 0.
736
737 // Move EDX to EAX.
buzbee2700f7e2014-03-07 09:46:20 -0800738 OpRegCopy(rs_r0, rs_r2);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800739
740 // Move sign bit to bit 0, zeroing the rest.
buzbee091cc402014-03-31 10:14:40 -0700741 NewLIR2(kX86Shr32RI, rs_r2.GetReg(), 31);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800742
743 // EDX = EDX + EAX.
buzbee091cc402014-03-31 10:14:40 -0700744 NewLIR2(kX86Add32RR, rs_r2.GetReg(), rs_r0.GetReg());
Mark Mendell2bf31e62014-01-23 12:13:40 -0800745
746 // Quotient is in EDX.
747 if (!is_div) {
748 // We need to compute the remainder.
749 // Remainder is divisor - (quotient * imm).
buzbee2700f7e2014-03-07 09:46:20 -0800750 DCHECK(numerator_reg.Valid());
751 OpRegCopy(rs_r0, numerator_reg);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800752
753 // EAX = numerator * imm.
buzbee2700f7e2014-03-07 09:46:20 -0800754 OpRegRegImm(kOpMul, rs_r2, rs_r2, imm);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800755
Mark Mendell3a91f442014-09-02 12:44:24 -0400756 // EAX -= EDX.
buzbee091cc402014-03-31 10:14:40 -0700757 NewLIR2(kX86Sub32RR, rs_r0.GetReg(), rs_r2.GetReg());
Mark Mendell2bf31e62014-01-23 12:13:40 -0800758
759 // For this case, return the result in EAX.
Mark Mendell2bf31e62014-01-23 12:13:40 -0800760 }
Yixin Shou2ddd1752014-08-26 15:15:13 -0400761 done->target = NewLIR0(kPseudoTargetLabel);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800762 }
763
764 return rl_result;
765}
766
buzbee2700f7e2014-03-07 09:46:20 -0800767RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg_lo, RegStorage reg_hi,
768 bool is_div) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700769 UNUSED(rl_dest, reg_lo, reg_hi, is_div);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700770 LOG(FATAL) << "Unexpected use of GenDivRem for x86";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700771 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700772}
773
Mark Mendell2bf31e62014-01-23 12:13:40 -0800774RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -0700775 RegLocation rl_src2, bool is_div, int flags) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700776 UNUSED(rl_dest);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800777 // We have to use fixed registers, so flush all the temps.
Maxim Kazantsev6dccdc22014-08-18 18:43:55 +0700778
779 // Prepare for explicit register usage.
780 ExplicitTempRegisterLock(this, 3, &rs_r0, &rs_r1, &rs_r2);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800781
782 // Load LHS into EAX.
buzbee2700f7e2014-03-07 09:46:20 -0800783 LoadValueDirectFixed(rl_src1, rs_r0);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800784
785 // Load RHS into EBX.
buzbee2700f7e2014-03-07 09:46:20 -0800786 LoadValueDirectFixed(rl_src2, rs_r1);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800787
788 // Copy LHS sign bit into EDX.
789 NewLIR0(kx86Cdq32Da);
790
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -0700791 if ((flags & MIR_IGNORE_DIV_ZERO_CHECK) == 0) {
Mark Mendell2bf31e62014-01-23 12:13:40 -0800792 // Handle division by zero case.
Mingyao Yange643a172014-04-08 11:02:52 -0700793 GenDivZeroCheck(rs_r1);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800794 }
795
Yixin Shou2ddd1752014-08-26 15:15:13 -0400796 // Check if numerator is 0
797 OpRegImm(kOpCmp, rs_r0, 0);
798 LIR* branch = NewLIR2(kX86Jcc8, 0, kX86CondEq);
799
Mark Mendell2bf31e62014-01-23 12:13:40 -0800800 // Have to catch 0x80000000/-1 case, or we will get an exception!
buzbee2700f7e2014-03-07 09:46:20 -0800801 OpRegImm(kOpCmp, rs_r1, -1);
Maxim Kazantsev6dccdc22014-08-18 18:43:55 +0700802 LIR* minus_one_branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800803
804 // RHS is -1.
buzbee2700f7e2014-03-07 09:46:20 -0800805 OpRegImm(kOpCmp, rs_r0, 0x80000000);
Maxim Kazantsev6dccdc22014-08-18 18:43:55 +0700806 LIR* minint_branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800807
Yixin Shou2ddd1752014-08-26 15:15:13 -0400808 branch->target = NewLIR0(kPseudoTargetLabel);
809
Mark Mendell2bf31e62014-01-23 12:13:40 -0800810 // In 0x80000000/-1 case.
811 if (!is_div) {
812 // For DIV, EAX is already right. For REM, we need EDX 0.
buzbee2700f7e2014-03-07 09:46:20 -0800813 LoadConstantNoClobber(rs_r2, 0);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800814 }
815 LIR* done = NewLIR1(kX86Jmp8, 0);
816
817 // Expected case.
818 minus_one_branch->target = NewLIR0(kPseudoTargetLabel);
819 minint_branch->target = minus_one_branch->target;
buzbee091cc402014-03-31 10:14:40 -0700820 NewLIR1(kX86Idivmod32DaR, rs_r1.GetReg());
Mark Mendell2bf31e62014-01-23 12:13:40 -0800821 done->target = NewLIR0(kPseudoTargetLabel);
822
823 // Result is in EAX for div and EDX for rem.
buzbee091cc402014-03-31 10:14:40 -0700824 RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, rs_r0, INVALID_SREG, INVALID_SREG};
Mark Mendell2bf31e62014-01-23 12:13:40 -0800825 if (!is_div) {
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000826 rl_result.reg.SetReg(r2);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800827 }
828 return rl_result;
829}
830
Serban Constantinescu23abec92014-07-02 16:13:38 +0100831bool X86Mir2Lir::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) {
Dmitry Petrochenko6a58cb12014-04-02 17:27:59 +0700832 DCHECK(cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800833
nikolay serdjuk4ab6f502014-08-08 09:55:06 +0700834 if (is_long && !cu_->target64) {
835 /*
836 * We want to implement the following algorithm
837 * mov eax, low part of arg1
838 * mov edx, high part of arg1
839 * mov ebx, low part of arg2
840 * mov ecx, high part of arg2
841 * mov edi, eax
842 * sub edi, ebx
843 * mov edi, edx
844 * sbb edi, ecx
845 * is_min ? "cmovgel eax, ebx" : "cmovll eax, ebx"
846 * is_min ? "cmovgel edx, ecx" : "cmovll edx, ecx"
847 *
848 * The algorithm above needs 5 registers: a pair for the first operand
849 * (which later will be used as result), a pair for the second operand
850 * and a temp register (e.g. 'edi') for intermediate calculations.
851 * Ideally we have 6 GP caller-save registers in 32-bit mode. They are:
852 * 'eax', 'ebx', 'ecx', 'edx', 'esi' and 'edi'. So there should be
853 * always enough registers to operate on. Practically, there is a pair
854 * of registers 'edi' and 'esi' which holds promoted values and
855 * sometimes should be treated as 'callee save'. If one of the operands
856 * is in the promoted registers then we have enough register to
857 * operate on. Otherwise there is lack of resources and we have to
858 * save 'edi' before calculations and restore after.
859 */
860
861 RegLocation rl_src1 = info->args[0];
862 RegLocation rl_src2 = info->args[2];
863 RegLocation rl_dest = InlineTargetWide(info);
864 int res_vreg, src1_vreg, src2_vreg;
865
Mark Mendella65c1db2014-10-21 17:44:32 -0400866 if (rl_dest.s_reg_low == INVALID_SREG) {
867 // Result is unused, the code is dead. Inlining successful, no code generated.
868 return true;
869 }
870
nikolay serdjuk4ab6f502014-08-08 09:55:06 +0700871 /*
872 * If the result register is the same as the second element, then we
873 * need to be careful. The reason is that the first copy will
874 * inadvertently clobber the second element with the first one thus
875 * yielding the wrong result. Thus we do a swap in that case.
876 */
877 res_vreg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
878 src2_vreg = mir_graph_->SRegToVReg(rl_src2.s_reg_low);
879 if (res_vreg == src2_vreg) {
880 std::swap(rl_src1, rl_src2);
881 }
882
883 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
884 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
885
886 // Pick the first integer as min/max.
887 OpRegCopyWide(rl_result.reg, rl_src1.reg);
888
889 /*
890 * If the integers are both in the same register, then there is
891 * nothing else to do because they are equal and we have already
892 * moved one into the result.
893 */
894 src1_vreg = mir_graph_->SRegToVReg(rl_src1.s_reg_low);
895 src2_vreg = mir_graph_->SRegToVReg(rl_src2.s_reg_low);
896 if (src1_vreg == src2_vreg) {
897 StoreValueWide(rl_dest, rl_result);
898 return true;
899 }
900
901 // Free registers to make some room for the second operand.
902 // But don't try to free ourselves or promoted registers.
903 if (res_vreg != src1_vreg &&
904 IsTemp(rl_src1.reg.GetLow()) && IsTemp(rl_src1.reg.GetHigh())) {
905 FreeTemp(rl_src1.reg);
906 }
907 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
908
909 // Do we have a free register for intermediate calculations?
910 RegStorage tmp = AllocTemp(false);
911 if (tmp == RegStorage::InvalidReg()) {
912 /*
913 * No, will use 'edi'.
914 *
915 * As mentioned above we have 4 temporary and 2 promotable
916 * caller-save registers. Therefore, we assume that a free
917 * register can be allocated only if 'esi' and 'edi' are
918 * already used as operands. If number of promotable registers
919 * increases from 2 to 4 then our assumption fails and operand
920 * data is corrupted.
921 * Let's DCHECK it.
922 */
923 DCHECK(IsTemp(rl_src2.reg.GetLow()) &&
924 IsTemp(rl_src2.reg.GetHigh()) &&
925 IsTemp(rl_result.reg.GetLow()) &&
926 IsTemp(rl_result.reg.GetHigh()));
927 tmp = rs_rDI;
928 NewLIR1(kX86Push32R, tmp.GetReg());
929 }
930
931 // Now we are ready to do calculations.
932 OpRegReg(kOpMov, tmp, rl_result.reg.GetLow());
933 OpRegReg(kOpSub, tmp, rl_src2.reg.GetLow());
934 OpRegReg(kOpMov, tmp, rl_result.reg.GetHigh());
935 OpRegReg(kOpSbc, tmp, rl_src2.reg.GetHigh());
936
937 // Let's put pop 'edi' here to break a bit the dependency chain.
938 if (tmp == rs_rDI) {
939 NewLIR1(kX86Pop32R, tmp.GetReg());
940 }
941
942 // Conditionally move the other integer into the destination register.
943 ConditionCode cc = is_min ? kCondGe : kCondLt;
944 OpCondRegReg(kOpCmov, cc, rl_result.reg.GetLow(), rl_src2.reg.GetLow());
945 OpCondRegReg(kOpCmov, cc, rl_result.reg.GetHigh(), rl_src2.reg.GetHigh());
946 StoreValueWide(rl_dest, rl_result);
947 return true;
Serban Constantinescu23abec92014-07-02 16:13:38 +0100948 }
949
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800950 // Get the two arguments to the invoke and place them in GP registers.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700951 RegLocation rl_src1 = info->args[0];
nikolay serdjukc5e4ce12014-06-10 17:07:10 +0700952 RegLocation rl_src2 = (is_long) ? info->args[2] : info->args[1];
953 rl_src1 = (is_long) ? LoadValueWide(rl_src1, kCoreReg) : LoadValue(rl_src1, kCoreReg);
954 rl_src2 = (is_long) ? LoadValueWide(rl_src2, kCoreReg) : LoadValue(rl_src2, kCoreReg);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800955
nikolay serdjukc5e4ce12014-06-10 17:07:10 +0700956 RegLocation rl_dest = (is_long) ? InlineTargetWide(info) : InlineTarget(info);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700957 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800958
959 /*
960 * If the result register is the same as the second element, then we need to be careful.
961 * The reason is that the first copy will inadvertently clobber the second element with
962 * the first one thus yielding the wrong result. Thus we do a swap in that case.
963 */
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000964 if (rl_result.reg.GetReg() == rl_src2.reg.GetReg()) {
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800965 std::swap(rl_src1, rl_src2);
966 }
967
968 // Pick the first integer as min/max.
buzbee2700f7e2014-03-07 09:46:20 -0800969 OpRegCopy(rl_result.reg, rl_src1.reg);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800970
971 // If the integers are both in the same register, then there is nothing else to do
972 // because they are equal and we have already moved one into the result.
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000973 if (rl_src1.reg.GetReg() != rl_src2.reg.GetReg()) {
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800974 // It is possible we didn't pick correctly so do the actual comparison now.
buzbee2700f7e2014-03-07 09:46:20 -0800975 OpRegReg(kOpCmp, rl_src1.reg, rl_src2.reg);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800976
977 // Conditionally move the other integer into the destination register.
978 ConditionCode condition_code = is_min ? kCondGt : kCondLt;
buzbee2700f7e2014-03-07 09:46:20 -0800979 OpCondRegReg(kOpCmov, condition_code, rl_result.reg, rl_src2.reg);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800980 }
981
nikolay serdjukc5e4ce12014-06-10 17:07:10 +0700982 if (is_long) {
Vladimir Markoe508a202013-11-04 15:24:22 +0000983 StoreValueWide(rl_dest, rl_result);
984 } else {
Vladimir Markoe508a202013-11-04 15:24:22 +0000985 StoreValue(rl_dest, rl_result);
986 }
987 return true;
988}
989
nikolay serdjukc5e4ce12014-06-10 17:07:10 +0700990bool X86Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
Alexei Zavjaloveb24bae2014-07-08 16:27:17 +0700991 RegLocation rl_src_address = info->args[0]; // long address
992 RegLocation rl_address;
993 if (!cu_->target64) {
994 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[0]
995 rl_address = LoadValue(rl_src_address, kCoreReg);
996 } else {
997 rl_address = LoadValueWide(rl_src_address, kCoreReg);
998 }
999 RegLocation rl_dest = size == k64 ? InlineTargetWide(info) : InlineTarget(info);
1000 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1001 // Unaligned access is allowed on x86.
1002 LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
1003 if (size == k64) {
1004 StoreValueWide(rl_dest, rl_result);
1005 } else {
1006 DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
1007 StoreValue(rl_dest, rl_result);
1008 }
1009 return true;
nikolay serdjukc5e4ce12014-06-10 17:07:10 +07001010}
1011
Vladimir Markoe508a202013-11-04 15:24:22 +00001012bool X86Mir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
Alexei Zavjaloveb24bae2014-07-08 16:27:17 +07001013 RegLocation rl_src_address = info->args[0]; // long address
1014 RegLocation rl_address;
1015 if (!cu_->target64) {
1016 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[0]
1017 rl_address = LoadValue(rl_src_address, kCoreReg);
1018 } else {
1019 rl_address = LoadValueWide(rl_src_address, kCoreReg);
1020 }
1021 RegLocation rl_src_value = info->args[2]; // [size] value
1022 RegLocation rl_value;
1023 if (size == k64) {
1024 // Unaligned access is allowed on x86.
1025 rl_value = LoadValueWide(rl_src_value, kCoreReg);
1026 } else {
1027 DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
1028 // In 32-bit mode the only EAX..EDX registers can be used with Mov8MR.
1029 if (!cu_->target64 && size == kSignedByte) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001030 rl_src_value = UpdateLocTyped(rl_src_value);
Alexei Zavjaloveb24bae2014-07-08 16:27:17 +07001031 if (rl_src_value.location == kLocPhysReg && !IsByteRegister(rl_src_value.reg)) {
1032 RegStorage temp = AllocateByteRegister();
1033 OpRegCopy(temp, rl_src_value.reg);
1034 rl_value.reg = temp;
1035 } else {
1036 rl_value = LoadValue(rl_src_value, kCoreReg);
1037 }
1038 } else {
1039 rl_value = LoadValue(rl_src_value, kCoreReg);
1040 }
1041 }
1042 StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
1043 return true;
Vladimir Markoe508a202013-11-04 15:24:22 +00001044}
1045
buzbee2700f7e2014-03-07 09:46:20 -08001046void X86Mir2Lir::OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale, int offset) {
1047 NewLIR5(kX86Lea32RA, r_base.GetReg(), reg1.GetReg(), reg2.GetReg(), scale, offset);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001048}
1049
Ian Rogersdd7624d2014-03-14 17:43:00 -07001050void X86Mir2Lir::OpTlsCmp(ThreadOffset<4> offset, int val) {
Andreas Gampe2f244e92014-05-08 03:35:25 -07001051 DCHECK_EQ(kX86, cu_->instruction_set);
1052 NewLIR2(kX86Cmp16TI8, offset.Int32Value(), val);
1053}
1054
1055void X86Mir2Lir::OpTlsCmp(ThreadOffset<8> offset, int val) {
1056 DCHECK_EQ(kX86_64, cu_->instruction_set);
Ian Rogers468532e2013-08-05 10:56:33 -07001057 NewLIR2(kX86Cmp16TI8, offset.Int32Value(), val);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001058}
1059
buzbee2700f7e2014-03-07 09:46:20 -08001060static bool IsInReg(X86Mir2Lir *pMir2Lir, const RegLocation &rl, RegStorage reg) {
1061 return rl.reg.Valid() && rl.reg.GetReg() == reg.GetReg() && (pMir2Lir->IsLive(reg) || rl.home);
Yevgeny Rouband3a2dfa2014-03-18 15:55:16 +07001062}
1063
Vladimir Marko1c282e22013-11-21 14:49:47 +00001064bool X86Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
Dmitry Petrochenko6a58cb12014-04-02 17:27:59 +07001065 DCHECK(cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64);
Vladimir Markoc29bb612013-11-27 16:47:25 +00001066 // Unused - RegLocation rl_src_unsafe = info->args[0];
1067 RegLocation rl_src_obj = info->args[1]; // Object - known non-null
1068 RegLocation rl_src_offset = info->args[2]; // long low
Chao-ying Fu021b60f2014-07-09 11:32:31 -07001069 if (!cu_->target64) {
1070 rl_src_offset = NarrowRegLoc(rl_src_offset); // ignore high half in info->args[3]
1071 }
Vladimir Markoc29bb612013-11-27 16:47:25 +00001072 RegLocation rl_src_expected = info->args[4]; // int, long or Object
1073 // If is_long, high half is in info->args[5]
1074 RegLocation rl_src_new_value = info->args[is_long ? 6 : 5]; // int, long or Object
1075 // If is_long, high half is in info->args[7]
1076
nikolay serdjukc5e4ce12014-06-10 17:07:10 +07001077 if (is_long && cu_->target64) {
1078 // RAX must hold expected for CMPXCHG. Neither rl_new_value, nor r_ptr may be in RAX.
Chao-ying Fu021b60f2014-07-09 11:32:31 -07001079 FlushReg(rs_r0q);
1080 Clobber(rs_r0q);
1081 LockTemp(rs_r0q);
nikolay serdjukc5e4ce12014-06-10 17:07:10 +07001082
1083 RegLocation rl_object = LoadValue(rl_src_obj, kRefReg);
1084 RegLocation rl_new_value = LoadValueWide(rl_src_new_value, kCoreReg);
Chao-ying Fu021b60f2014-07-09 11:32:31 -07001085 RegLocation rl_offset = LoadValueWide(rl_src_offset, kCoreReg);
1086 LoadValueDirectWide(rl_src_expected, rs_r0q);
Andreas Gampeccc60262014-07-04 18:02:38 -07001087 NewLIR5(kX86LockCmpxchg64AR, rl_object.reg.GetReg(), rl_offset.reg.GetReg(), 0, 0,
1088 rl_new_value.reg.GetReg());
nikolay serdjukc5e4ce12014-06-10 17:07:10 +07001089
1090 // After a store we need to insert barrier in case of potential load. Since the
1091 // locked cmpxchg has full barrier semantics, only a scheduling barrier will be generated.
Hans Boehm48f5c472014-06-27 14:50:10 -07001092 GenMemBarrier(kAnyAny);
nikolay serdjukc5e4ce12014-06-10 17:07:10 +07001093
Chao-ying Fu021b60f2014-07-09 11:32:31 -07001094 FreeTemp(rs_r0q);
nikolay serdjukc5e4ce12014-06-10 17:07:10 +07001095 } else if (is_long) {
Yevgeny Rouband3a2dfa2014-03-18 15:55:16 +07001096 // TODO: avoid unnecessary loads of SI and DI when the values are in registers.
1097 // TODO: CFI support.
Vladimir Marko70b797d2013-12-03 15:25:24 +00001098 FlushAllRegs();
1099 LockCallTemps();
buzbee091cc402014-03-31 10:14:40 -07001100 RegStorage r_tmp1 = RegStorage::MakeRegPair(rs_rAX, rs_rDX);
1101 RegStorage r_tmp2 = RegStorage::MakeRegPair(rs_rBX, rs_rCX);
buzbee2700f7e2014-03-07 09:46:20 -08001102 LoadValueDirectWideFixed(rl_src_expected, r_tmp1);
1103 LoadValueDirectWideFixed(rl_src_new_value, r_tmp2);
buzbee695d13a2014-04-19 13:32:20 -07001104 // FIXME: needs 64-bit update.
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001105 const bool obj_in_di = IsInReg(this, rl_src_obj, rs_rDI);
1106 const bool obj_in_si = IsInReg(this, rl_src_obj, rs_rSI);
1107 DCHECK(!obj_in_si || !obj_in_di);
1108 const bool off_in_di = IsInReg(this, rl_src_offset, rs_rDI);
1109 const bool off_in_si = IsInReg(this, rl_src_offset, rs_rSI);
1110 DCHECK(!off_in_si || !off_in_di);
1111 // If obj/offset is in a reg, use that reg. Otherwise, use the empty reg.
1112 RegStorage rs_obj = obj_in_di ? rs_rDI : obj_in_si ? rs_rSI : !off_in_di ? rs_rDI : rs_rSI;
1113 RegStorage rs_off = off_in_si ? rs_rSI : off_in_di ? rs_rDI : !obj_in_si ? rs_rSI : rs_rDI;
1114 bool push_di = (!obj_in_di && !off_in_di) && (rs_obj == rs_rDI || rs_off == rs_rDI);
1115 bool push_si = (!obj_in_si && !off_in_si) && (rs_obj == rs_rSI || rs_off == rs_rSI);
1116 if (push_di) {
1117 NewLIR1(kX86Push32R, rs_rDI.GetReg());
1118 MarkTemp(rs_rDI);
1119 LockTemp(rs_rDI);
1120 }
1121 if (push_si) {
1122 NewLIR1(kX86Push32R, rs_rSI.GetReg());
1123 MarkTemp(rs_rSI);
1124 LockTemp(rs_rSI);
1125 }
1126 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
1127 const size_t push_offset = (push_si ? 4u : 0u) + (push_di ? 4u : 0u);
Ian Rogersb28c1c02014-11-08 11:21:21 -08001128 const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001129 if (!obj_in_si && !obj_in_di) {
Ian Rogersb28c1c02014-11-08 11:21:21 -08001130 LoadWordDisp(rs_rSP, SRegOffset(rl_src_obj.s_reg_low) + push_offset, rs_obj);
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001131 // Dalvik register annotation in LoadBaseIndexedDisp() used wrong offset. Fix it.
1132 DCHECK(!DECODE_ALIAS_INFO_WIDE(last_lir_insn_->flags.alias_info));
1133 int reg_id = DECODE_ALIAS_INFO_REG(last_lir_insn_->flags.alias_info) - push_offset / 4u;
1134 AnnotateDalvikRegAccess(last_lir_insn_, reg_id, true, false);
1135 }
1136 if (!off_in_si && !off_in_di) {
Ian Rogersb28c1c02014-11-08 11:21:21 -08001137 LoadWordDisp(rs_rSP, SRegOffset(rl_src_offset.s_reg_low) + push_offset, rs_off);
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001138 // Dalvik register annotation in LoadBaseIndexedDisp() used wrong offset. Fix it.
1139 DCHECK(!DECODE_ALIAS_INFO_WIDE(last_lir_insn_->flags.alias_info));
1140 int reg_id = DECODE_ALIAS_INFO_REG(last_lir_insn_->flags.alias_info) - push_offset / 4u;
1141 AnnotateDalvikRegAccess(last_lir_insn_, reg_id, true, false);
1142 }
1143 NewLIR4(kX86LockCmpxchg64A, rs_obj.GetReg(), rs_off.GetReg(), 0, 0);
Razvan A Lupusoru99ad7232014-02-25 17:41:08 -08001144
Hans Boehm48f5c472014-06-27 14:50:10 -07001145 // After a store we need to insert barrier to prevent reordering with either
1146 // earlier or later memory accesses. Since
1147 // locked cmpxchg has full barrier semantics, only a scheduling barrier will be generated,
1148 // and it will be associated with the cmpxchg instruction, preventing both.
1149 GenMemBarrier(kAnyAny);
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001150
1151 if (push_si) {
1152 FreeTemp(rs_rSI);
1153 UnmarkTemp(rs_rSI);
1154 NewLIR1(kX86Pop32R, rs_rSI.GetReg());
1155 }
1156 if (push_di) {
1157 FreeTemp(rs_rDI);
1158 UnmarkTemp(rs_rDI);
1159 NewLIR1(kX86Pop32R, rs_rDI.GetReg());
1160 }
Vladimir Marko70b797d2013-12-03 15:25:24 +00001161 FreeCallTemps();
Vladimir Markoc29bb612013-11-27 16:47:25 +00001162 } else {
1163 // EAX must hold expected for CMPXCHG. Neither rl_new_value, nor r_ptr may be in EAX.
buzbee2700f7e2014-03-07 09:46:20 -08001164 FlushReg(rs_r0);
buzbee091cc402014-03-31 10:14:40 -07001165 Clobber(rs_r0);
buzbee2700f7e2014-03-07 09:46:20 -08001166 LockTemp(rs_r0);
Vladimir Markoc29bb612013-11-27 16:47:25 +00001167
buzbeea0cd2d72014-06-01 09:33:49 -07001168 RegLocation rl_object = LoadValue(rl_src_obj, kRefReg);
buzbee7c02e912014-10-03 13:14:17 -07001169 RegLocation rl_new_value = LoadValue(rl_src_new_value, LocToRegClass(rl_src_new_value));
Vladimir Markoc29bb612013-11-27 16:47:25 +00001170
1171 if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
1172 // Mark card for object assuming new value is stored.
buzbee091cc402014-03-31 10:14:40 -07001173 FreeTemp(rs_r0); // Temporarily release EAX for MarkGCCard().
Vladimir Marko743b98c2014-11-24 19:45:41 +00001174 MarkGCCard(0, rl_new_value.reg, rl_object.reg);
buzbee091cc402014-03-31 10:14:40 -07001175 LockTemp(rs_r0);
Vladimir Markoc29bb612013-11-27 16:47:25 +00001176 }
1177
Chao-ying Fu021b60f2014-07-09 11:32:31 -07001178 RegLocation rl_offset;
1179 if (cu_->target64) {
1180 rl_offset = LoadValueWide(rl_src_offset, kCoreReg);
1181 } else {
1182 rl_offset = LoadValue(rl_src_offset, kCoreReg);
1183 }
buzbee2700f7e2014-03-07 09:46:20 -08001184 LoadValueDirect(rl_src_expected, rs_r0);
Andreas Gampeccc60262014-07-04 18:02:38 -07001185 NewLIR5(kX86LockCmpxchgAR, rl_object.reg.GetReg(), rl_offset.reg.GetReg(), 0, 0,
1186 rl_new_value.reg.GetReg());
Vladimir Markoc29bb612013-11-27 16:47:25 +00001187
Hans Boehm48f5c472014-06-27 14:50:10 -07001188 // After a store we need to insert barrier to prevent reordering with either
1189 // earlier or later memory accesses. Since
1190 // locked cmpxchg has full barrier semantics, only a scheduling barrier will be generated,
1191 // and it will be associated with the cmpxchg instruction, preventing both.
1192 GenMemBarrier(kAnyAny);
Razvan A Lupusoru99ad7232014-02-25 17:41:08 -08001193
buzbee091cc402014-03-31 10:14:40 -07001194 FreeTemp(rs_r0);
Vladimir Markoc29bb612013-11-27 16:47:25 +00001195 }
1196
1197 // Convert ZF to boolean
1198 RegLocation rl_dest = InlineTarget(info); // boolean place for result
1199 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Ian Rogers0f9b9c52014-06-09 01:32:12 -07001200 RegStorage result_reg = rl_result.reg;
1201
Chao-ying Fu7e399fd2014-06-10 18:11:11 -07001202 // For 32-bit, SETcc only works with EAX..EDX.
1203 if (!IsByteRegister(result_reg)) {
Ian Rogers0f9b9c52014-06-09 01:32:12 -07001204 result_reg = AllocateByteRegister();
Ian Rogers0f9b9c52014-06-09 01:32:12 -07001205 }
1206 NewLIR2(kX86Set8R, result_reg.GetReg(), kX86CondZ);
1207 NewLIR2(kX86Movzx8RR, rl_result.reg.GetReg(), result_reg.GetReg());
1208 if (IsTemp(result_reg)) {
1209 FreeTemp(result_reg);
1210 }
Vladimir Markoc29bb612013-11-27 16:47:25 +00001211 StoreValue(rl_dest, rl_result);
1212 return true;
Brian Carlstrom7940e442013-07-12 13:46:57 -07001213}
1214
Yixin Shou8c914c02014-07-28 14:17:09 -04001215void X86Mir2Lir::SwapBits(RegStorage result_reg, int shift, int32_t value) {
1216 RegStorage r_temp = AllocTemp();
1217 OpRegCopy(r_temp, result_reg);
1218 OpRegImm(kOpLsr, result_reg, shift);
1219 OpRegImm(kOpAnd, r_temp, value);
1220 OpRegImm(kOpAnd, result_reg, value);
1221 OpRegImm(kOpLsl, r_temp, shift);
1222 OpRegReg(kOpOr, result_reg, r_temp);
1223 FreeTemp(r_temp);
1224}
1225
1226void X86Mir2Lir::SwapBits64(RegStorage result_reg, int shift, int64_t value) {
1227 RegStorage r_temp = AllocTempWide();
1228 OpRegCopy(r_temp, result_reg);
1229 OpRegImm(kOpLsr, result_reg, shift);
1230 RegStorage r_value = AllocTempWide();
1231 LoadConstantWide(r_value, value);
1232 OpRegReg(kOpAnd, r_temp, r_value);
1233 OpRegReg(kOpAnd, result_reg, r_value);
1234 OpRegImm(kOpLsl, r_temp, shift);
1235 OpRegReg(kOpOr, result_reg, r_temp);
1236 FreeTemp(r_temp);
1237 FreeTemp(r_value);
1238}
1239
1240bool X86Mir2Lir::GenInlinedReverseBits(CallInfo* info, OpSize size) {
1241 RegLocation rl_src_i = info->args[0];
1242 RegLocation rl_i = (size == k64) ? LoadValueWide(rl_src_i, kCoreReg)
1243 : LoadValue(rl_src_i, kCoreReg);
1244 RegLocation rl_dest = (size == k64) ? InlineTargetWide(info) : InlineTarget(info);
1245 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1246 if (size == k64) {
1247 if (cu_->instruction_set == kX86_64) {
1248 /* Use one bswap instruction to reverse byte order first and then use 3 rounds of
1249 swapping bits to reverse bits in a long number x. Using bswap to save instructions
1250 compared to generic luni implementation which has 5 rounds of swapping bits.
1251 x = bswap x
1252 x = (x & 0x5555555555555555) << 1 | (x >> 1) & 0x5555555555555555;
1253 x = (x & 0x3333333333333333) << 2 | (x >> 2) & 0x3333333333333333;
1254 x = (x & 0x0F0F0F0F0F0F0F0F) << 4 | (x >> 4) & 0x0F0F0F0F0F0F0F0F;
1255 */
1256 OpRegReg(kOpRev, rl_result.reg, rl_i.reg);
1257 SwapBits64(rl_result.reg, 1, 0x5555555555555555);
1258 SwapBits64(rl_result.reg, 2, 0x3333333333333333);
1259 SwapBits64(rl_result.reg, 4, 0x0f0f0f0f0f0f0f0f);
1260 StoreValueWide(rl_dest, rl_result);
1261 return true;
1262 }
1263 RegStorage r_i_low = rl_i.reg.GetLow();
1264 if (rl_i.reg.GetLowReg() == rl_result.reg.GetLowReg()) {
1265 // First REV shall clobber rl_result.reg.GetLowReg(), save the value in a temp for the second
1266 // REV.
1267 r_i_low = AllocTemp();
1268 OpRegCopy(r_i_low, rl_i.reg);
1269 }
1270 OpRegReg(kOpRev, rl_result.reg.GetLow(), rl_i.reg.GetHigh());
1271 OpRegReg(kOpRev, rl_result.reg.GetHigh(), r_i_low);
1272 if (rl_i.reg.GetLowReg() == rl_result.reg.GetLowReg()) {
1273 FreeTemp(r_i_low);
1274 }
1275 SwapBits(rl_result.reg.GetLow(), 1, 0x55555555);
1276 SwapBits(rl_result.reg.GetLow(), 2, 0x33333333);
1277 SwapBits(rl_result.reg.GetLow(), 4, 0x0f0f0f0f);
1278 SwapBits(rl_result.reg.GetHigh(), 1, 0x55555555);
1279 SwapBits(rl_result.reg.GetHigh(), 2, 0x33333333);
1280 SwapBits(rl_result.reg.GetHigh(), 4, 0x0f0f0f0f);
1281 StoreValueWide(rl_dest, rl_result);
1282 } else {
1283 OpRegReg(kOpRev, rl_result.reg, rl_i.reg);
1284 SwapBits(rl_result.reg, 1, 0x55555555);
1285 SwapBits(rl_result.reg, 2, 0x33333333);
1286 SwapBits(rl_result.reg, 4, 0x0f0f0f0f);
1287 StoreValue(rl_dest, rl_result);
1288 }
1289 return true;
1290}
1291
buzbee2700f7e2014-03-07 09:46:20 -08001292LIR* X86Mir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
Mark Mendell27dee8b2014-12-01 19:06:12 -05001293 if (cu_->target64) {
1294 // We can do this directly using RIP addressing.
1295 // We don't know the proper offset for the value, so pick one that will force
1296 // 4 byte offset. We will fix this up in the assembler later to have the right
1297 // value.
1298 ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
1299 LIR* res = NewLIR3(kX86Mov32RM, reg.GetReg(), kRIPReg, 256);
1300 res->target = target;
1301 res->flags.fixup = kFixupLoad;
1302 return res;
1303 }
1304
Mark Mendell55d0eac2014-02-06 11:02:52 -08001305 CHECK(base_of_code_ != nullptr);
1306
1307 // Address the start of the method
1308 RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07001309 if (rl_method.wide) {
1310 LoadValueDirectWideFixed(rl_method, reg);
1311 } else {
1312 LoadValueDirectFixed(rl_method, reg);
1313 }
Mark Mendell55d0eac2014-02-06 11:02:52 -08001314 store_method_addr_used_ = true;
1315
1316 // Load the proper value from the literal area.
1317 // We don't know the proper offset for the value, so pick one that will force
1318 // 4 byte offset. We will fix this up in the assembler later to have the right
1319 // value.
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001320 ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
buzbee2700f7e2014-03-07 09:46:20 -08001321 LIR *res = RawLIR(current_dalvik_offset_, kX86Mov32RM, reg.GetReg(), reg.GetReg(), 256,
1322 0, 0, target);
Mark Mendell55d0eac2014-02-06 11:02:52 -08001323 res->target = target;
1324 res->flags.fixup = kFixupLoad;
Mark Mendell55d0eac2014-02-06 11:02:52 -08001325 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -07001326}
1327
buzbee2700f7e2014-03-07 09:46:20 -08001328LIR* X86Mir2Lir::OpVldm(RegStorage r_base, int count) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001329 UNUSED(r_base, count);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001330 LOG(FATAL) << "Unexpected use of OpVldm for x86";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001331 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001332}
1333
buzbee2700f7e2014-03-07 09:46:20 -08001334LIR* X86Mir2Lir::OpVstm(RegStorage r_base, int count) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001335 UNUSED(r_base, count);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001336 LOG(FATAL) << "Unexpected use of OpVstm for x86";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001337 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001338}
1339
1340void X86Mir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
1341 RegLocation rl_result, int lit,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001342 int first_bit, int second_bit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001343 UNUSED(lit);
buzbee2700f7e2014-03-07 09:46:20 -08001344 RegStorage t_reg = AllocTemp();
1345 OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit);
1346 OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001347 FreeTemp(t_reg);
1348 if (first_bit != 0) {
buzbee2700f7e2014-03-07 09:46:20 -08001349 OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001350 }
1351}
1352
Mingyao Yange643a172014-04-08 11:02:52 -07001353void X86Mir2Lir::GenDivZeroCheckWide(RegStorage reg) {
Elena Sayapinadd644502014-07-01 18:39:52 +07001354 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -07001355 DCHECK(reg.Is64Bit());
Razvan A Lupusoru090dd442013-12-20 14:35:03 -08001356
Chao-ying Fua0147762014-06-06 18:38:49 -07001357 NewLIR2(kX86Cmp64RI8, reg.GetReg(), 0);
1358 } else {
1359 DCHECK(reg.IsPair());
1360
1361 // We are not supposed to clobber the incoming storage, so allocate a temporary.
1362 RegStorage t_reg = AllocTemp();
1363 // Doing an OR is a quick way to check if both registers are zero. This will set the flags.
1364 OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh());
1365 // The temp is no longer needed so free it at this time.
1366 FreeTemp(t_reg);
1367 }
Razvan A Lupusoru090dd442013-12-20 14:35:03 -08001368
1369 // In case of zero, throw ArithmeticException.
Mingyao Yange643a172014-04-08 11:02:52 -07001370 GenDivZeroCheck(kCondEq);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001371}
1372
Mingyao Yang80365d92014-04-18 12:10:58 -07001373void X86Mir2Lir::GenArrayBoundsCheck(RegStorage index,
1374 RegStorage array_base,
1375 int len_offset) {
1376 class ArrayBoundsCheckSlowPath : public Mir2Lir::LIRSlowPath {
1377 public:
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001378 ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch_in,
1379 RegStorage index_in, RegStorage array_base_in, int32_t len_offset_in)
1380 : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch_in),
1381 index_(index_in), array_base_(array_base_in), len_offset_(len_offset_in) {
Mingyao Yang80365d92014-04-18 12:10:58 -07001382 }
1383
1384 void Compile() OVERRIDE {
1385 m2l_->ResetRegPool();
1386 m2l_->ResetDefTracking();
Mingyao Yang6ffcfa02014-04-25 11:06:00 -07001387 GenerateTargetLabel(kPseudoThrowTarget);
Mingyao Yang80365d92014-04-18 12:10:58 -07001388
1389 RegStorage new_index = index_;
1390 // Move index out of kArg1, either directly to kArg0, or to kArg2.
Serguei Katkov4c7cc152014-06-24 00:50:02 +07001391 // TODO: clean-up to check not a number but with type
Andreas Gampeccc60262014-07-04 18:02:38 -07001392 if (index_ == m2l_->TargetReg(kArg1, kNotWide)) {
1393 if (array_base_ == m2l_->TargetReg(kArg0, kRef)) {
1394 m2l_->OpRegCopy(m2l_->TargetReg(kArg2, kNotWide), index_);
1395 new_index = m2l_->TargetReg(kArg2, kNotWide);
Mingyao Yang80365d92014-04-18 12:10:58 -07001396 } else {
Andreas Gampeccc60262014-07-04 18:02:38 -07001397 m2l_->OpRegCopy(m2l_->TargetReg(kArg0, kNotWide), index_);
1398 new_index = m2l_->TargetReg(kArg0, kNotWide);
Mingyao Yang80365d92014-04-18 12:10:58 -07001399 }
1400 }
1401 // Load array length to kArg1.
Andreas Gampe98430592014-07-27 19:44:50 -07001402 X86Mir2Lir* x86_m2l = static_cast<X86Mir2Lir*>(m2l_);
1403 x86_m2l->OpRegMem(kOpMov, m2l_->TargetReg(kArg1, kNotWide), array_base_, len_offset_);
1404 x86_m2l->CallRuntimeHelperRegReg(kQuickThrowArrayBounds, new_index,
1405 m2l_->TargetReg(kArg1, kNotWide), true);
Mingyao Yang80365d92014-04-18 12:10:58 -07001406 }
1407
1408 private:
1409 const RegStorage index_;
1410 const RegStorage array_base_;
1411 const int32_t len_offset_;
1412 };
1413
1414 OpRegMem(kOpCmp, index, array_base, len_offset);
Dave Allison69dfe512014-07-11 17:11:58 +00001415 MarkPossibleNullPointerException(0);
Mingyao Yang80365d92014-04-18 12:10:58 -07001416 LIR* branch = OpCondBranch(kCondUge, nullptr);
1417 AddSlowPath(new (arena_) ArrayBoundsCheckSlowPath(this, branch,
1418 index, array_base, len_offset));
1419}
1420
1421void X86Mir2Lir::GenArrayBoundsCheck(int32_t index,
1422 RegStorage array_base,
1423 int32_t len_offset) {
1424 class ArrayBoundsCheckSlowPath : public Mir2Lir::LIRSlowPath {
1425 public:
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001426 ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch_in,
1427 int32_t index_in, RegStorage array_base_in, int32_t len_offset_in)
1428 : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch_in),
1429 index_(index_in), array_base_(array_base_in), len_offset_(len_offset_in) {
Mingyao Yang80365d92014-04-18 12:10:58 -07001430 }
1431
1432 void Compile() OVERRIDE {
1433 m2l_->ResetRegPool();
1434 m2l_->ResetDefTracking();
Mingyao Yang6ffcfa02014-04-25 11:06:00 -07001435 GenerateTargetLabel(kPseudoThrowTarget);
Mingyao Yang80365d92014-04-18 12:10:58 -07001436
1437 // Load array length to kArg1.
Andreas Gampe98430592014-07-27 19:44:50 -07001438 X86Mir2Lir* x86_m2l = static_cast<X86Mir2Lir*>(m2l_);
1439 x86_m2l->OpRegMem(kOpMov, m2l_->TargetReg(kArg1, kNotWide), array_base_, len_offset_);
1440 x86_m2l->LoadConstant(m2l_->TargetReg(kArg0, kNotWide), index_);
1441 x86_m2l->CallRuntimeHelperRegReg(kQuickThrowArrayBounds, m2l_->TargetReg(kArg0, kNotWide),
1442 m2l_->TargetReg(kArg1, kNotWide), true);
Mingyao Yang80365d92014-04-18 12:10:58 -07001443 }
1444
1445 private:
1446 const int32_t index_;
1447 const RegStorage array_base_;
1448 const int32_t len_offset_;
1449 };
1450
1451 NewLIR3(IS_SIMM8(index) ? kX86Cmp32MI8 : kX86Cmp32MI, array_base.GetReg(), len_offset, index);
Dave Allison69dfe512014-07-11 17:11:58 +00001452 MarkPossibleNullPointerException(0);
Mingyao Yang80365d92014-04-18 12:10:58 -07001453 LIR* branch = OpCondBranch(kCondLs, nullptr);
1454 AddSlowPath(new (arena_) ArrayBoundsCheckSlowPath(this, branch,
1455 index, array_base, len_offset));
1456}
1457
Brian Carlstrom7940e442013-07-12 13:46:57 -07001458// Test suspend flag, return target of taken suspend branch
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001459LIR* X86Mir2Lir::OpTestSuspend(LIR* target) {
buzbee33ae5582014-06-12 14:56:32 -07001460 if (cu_->target64) {
Andreas Gampe2f244e92014-05-08 03:35:25 -07001461 OpTlsCmp(Thread::ThreadFlagsOffset<8>(), 0);
1462 } else {
1463 OpTlsCmp(Thread::ThreadFlagsOffset<4>(), 0);
1464 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07001465 return OpCondBranch((target == NULL) ? kCondNe : kCondEq, target);
1466}
1467
1468// Decrement register and branch on condition
buzbee2700f7e2014-03-07 09:46:20 -08001469LIR* X86Mir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001470 OpRegImm(kOpSub, reg, 1);
Yixin Shoua0dac3e2014-01-23 05:01:22 -08001471 return OpCondBranch(c_code, target);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001472}
1473
buzbee11b63d12013-08-27 07:34:17 -07001474bool X86Mir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001475 RegLocation rl_src, RegLocation rl_dest, int lit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001476 UNUSED(dalvik_opcode, is_div, rl_src, rl_dest, lit);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001477 LOG(FATAL) << "Unexpected use of smallLiteralDive in x86";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001478 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001479}
1480
Ian Rogerse2143c02014-03-28 08:47:16 -07001481bool X86Mir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001482 UNUSED(rl_src, rl_dest, lit);
Ian Rogerse2143c02014-03-28 08:47:16 -07001483 LOG(FATAL) << "Unexpected use of easyMultiply in x86";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001484 UNREACHABLE();
Ian Rogerse2143c02014-03-28 08:47:16 -07001485}
1486
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001487LIR* X86Mir2Lir::OpIT(ConditionCode cond, const char* guide) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001488 UNUSED(cond, guide);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001489 LOG(FATAL) << "Unexpected use of OpIT in x86";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001490 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001491}
1492
Dave Allison3da67a52014-04-02 17:03:45 -07001493void X86Mir2Lir::OpEndIT(LIR* it) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001494 UNUSED(it);
Dave Allison3da67a52014-04-02 17:03:45 -07001495 LOG(FATAL) << "Unexpected use of OpEndIT in x86";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001496 UNREACHABLE();
Dave Allison3da67a52014-04-02 17:03:45 -07001497}
1498
buzbee2700f7e2014-03-07 09:46:20 -08001499void X86Mir2Lir::GenImulRegImm(RegStorage dest, RegStorage src, int val) {
Mark Mendell4708dcd2014-01-22 09:05:18 -08001500 switch (val) {
1501 case 0:
buzbee2700f7e2014-03-07 09:46:20 -08001502 NewLIR2(kX86Xor32RR, dest.GetReg(), dest.GetReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001503 break;
1504 case 1:
1505 OpRegCopy(dest, src);
1506 break;
1507 default:
1508 OpRegRegImm(kOpMul, dest, src, val);
1509 break;
1510 }
1511}
1512
buzbee2700f7e2014-03-07 09:46:20 -08001513void X86Mir2Lir::GenImulMemImm(RegStorage dest, int sreg, int displacement, int val) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001514 UNUSED(sreg);
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001515 // All memory accesses below reference dalvik regs.
1516 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
1517
Mark Mendell4708dcd2014-01-22 09:05:18 -08001518 LIR *m;
1519 switch (val) {
1520 case 0:
buzbee2700f7e2014-03-07 09:46:20 -08001521 NewLIR2(kX86Xor32RR, dest.GetReg(), dest.GetReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001522 break;
Ian Rogersb28c1c02014-11-08 11:21:21 -08001523 case 1: {
1524 const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
1525 LoadBaseDisp(rs_rSP, displacement, dest, k32, kNotVolatile);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001526 break;
Ian Rogersb28c1c02014-11-08 11:21:21 -08001527 }
Mark Mendell4708dcd2014-01-22 09:05:18 -08001528 default:
buzbee091cc402014-03-31 10:14:40 -07001529 m = NewLIR4(IS_SIMM8(val) ? kX86Imul32RMI8 : kX86Imul32RMI, dest.GetReg(),
Ian Rogersb28c1c02014-11-08 11:21:21 -08001530 rs_rX86_SP_32.GetReg(), displacement, val);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001531 AnnotateDalvikRegAccess(m, displacement >> 2, true /* is_load */, true /* is_64bit */);
1532 break;
1533 }
1534}
1535
Andreas Gampec76c6142014-08-04 16:30:03 -07001536void X86Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07001537 RegLocation rl_src2, int flags) {
Andreas Gampec76c6142014-08-04 16:30:03 -07001538 if (!cu_->target64) {
1539 // Some x86 32b ops are fallback.
1540 switch (opcode) {
1541 case Instruction::NOT_LONG:
1542 case Instruction::DIV_LONG:
1543 case Instruction::DIV_LONG_2ADDR:
1544 case Instruction::REM_LONG:
1545 case Instruction::REM_LONG_2ADDR:
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07001546 Mir2Lir::GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
Andreas Gampec76c6142014-08-04 16:30:03 -07001547 return;
1548
1549 default:
1550 // Everything else we can handle.
1551 break;
1552 }
1553 }
1554
1555 switch (opcode) {
1556 case Instruction::NOT_LONG:
1557 GenNotLong(rl_dest, rl_src2);
1558 return;
1559
1560 case Instruction::ADD_LONG:
1561 case Instruction::ADD_LONG_2ADDR:
1562 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
1563 return;
1564
1565 case Instruction::SUB_LONG:
1566 case Instruction::SUB_LONG_2ADDR:
1567 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, false);
1568 return;
1569
1570 case Instruction::MUL_LONG:
1571 case Instruction::MUL_LONG_2ADDR:
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07001572 GenMulLong(opcode, rl_dest, rl_src1, rl_src2, flags);
Andreas Gampec76c6142014-08-04 16:30:03 -07001573 return;
1574
1575 case Instruction::DIV_LONG:
1576 case Instruction::DIV_LONG_2ADDR:
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07001577 GenDivRemLong(opcode, rl_dest, rl_src1, rl_src2, /*is_div*/ true, flags);
Andreas Gampec76c6142014-08-04 16:30:03 -07001578 return;
1579
1580 case Instruction::REM_LONG:
1581 case Instruction::REM_LONG_2ADDR:
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07001582 GenDivRemLong(opcode, rl_dest, rl_src1, rl_src2, /*is_div*/ false, flags);
Andreas Gampec76c6142014-08-04 16:30:03 -07001583 return;
1584
1585 case Instruction::AND_LONG_2ADDR:
1586 case Instruction::AND_LONG:
1587 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
1588 return;
1589
1590 case Instruction::OR_LONG:
1591 case Instruction::OR_LONG_2ADDR:
1592 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
1593 return;
1594
1595 case Instruction::XOR_LONG:
1596 case Instruction::XOR_LONG_2ADDR:
1597 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
1598 return;
1599
1600 case Instruction::NEG_LONG:
1601 GenNegLong(rl_dest, rl_src2);
1602 return;
1603
1604 default:
1605 LOG(FATAL) << "Invalid long arith op";
1606 return;
1607 }
1608}
1609
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07001610bool X86Mir2Lir::GenMulLongConst(RegLocation rl_dest, RegLocation rl_src1, int64_t val, int flags) {
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001611 // All memory accesses below reference dalvik regs.
1612 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
1613
Andreas Gampec76c6142014-08-04 16:30:03 -07001614 if (val == 0) {
Alexei Zavjalovd8191d02014-06-11 18:26:40 +07001615 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Andreas Gampec76c6142014-08-04 16:30:03 -07001616 if (cu_->target64) {
1617 OpRegReg(kOpXor, rl_result.reg, rl_result.reg);
Alexei Zavjalovd8191d02014-06-11 18:26:40 +07001618 } else {
buzbee2700f7e2014-03-07 09:46:20 -08001619 OpRegReg(kOpXor, rl_result.reg.GetLow(), rl_result.reg.GetLow());
1620 OpRegReg(kOpXor, rl_result.reg.GetHigh(), rl_result.reg.GetHigh());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001621 }
Andreas Gampec76c6142014-08-04 16:30:03 -07001622 StoreValueWide(rl_dest, rl_result);
1623 return true;
1624 } else if (val == 1) {
1625 StoreValueWide(rl_dest, rl_src1);
1626 return true;
1627 } else if (val == 2) {
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07001628 GenArithOpLong(Instruction::ADD_LONG, rl_dest, rl_src1, rl_src1, flags);
Andreas Gampec76c6142014-08-04 16:30:03 -07001629 return true;
1630 } else if (IsPowerOfTwo(val)) {
Andreas Gampe7e499922015-01-06 08:28:12 -08001631 int shift_amount = CTZ(val);
Alexei Zavjalovd8c3e362014-10-08 15:51:59 +07001632 if (!PartiallyIntersects(rl_src1, rl_dest)) {
Andreas Gampec76c6142014-08-04 16:30:03 -07001633 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
1634 RegLocation rl_result = GenShiftImmOpLong(Instruction::SHL_LONG, rl_dest, rl_src1,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07001635 shift_amount, flags);
Andreas Gampec76c6142014-08-04 16:30:03 -07001636 StoreValueWide(rl_dest, rl_result);
1637 return true;
1638 }
1639 }
Mark Mendell4708dcd2014-01-22 09:05:18 -08001640
Andreas Gampec76c6142014-08-04 16:30:03 -07001641 // Okay, on 32b just bite the bullet and do it, still better than the general case.
1642 if (!cu_->target64) {
Mark Mendell4708dcd2014-01-22 09:05:18 -08001643 int32_t val_lo = Low32Bits(val);
1644 int32_t val_hi = High32Bits(val);
Maxim Kazantsev6dccdc22014-08-18 18:43:55 +07001645 // Prepare for explicit register usage.
1646 ExplicitTempRegisterLock(this, 3, &rs_r0, &rs_r1, &rs_r2);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001647 rl_src1 = UpdateLocWideTyped(rl_src1);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001648 bool src1_in_reg = rl_src1.location == kLocPhysReg;
1649 int displacement = SRegOffset(rl_src1.s_reg_low);
1650
1651 // ECX <- 1H * 2L
1652 // EAX <- 1L * 2H
1653 if (src1_in_reg) {
buzbee2700f7e2014-03-07 09:46:20 -08001654 GenImulRegImm(rs_r1, rl_src1.reg.GetHigh(), val_lo);
1655 GenImulRegImm(rs_r0, rl_src1.reg.GetLow(), val_hi);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001656 } else {
buzbee2700f7e2014-03-07 09:46:20 -08001657 GenImulMemImm(rs_r1, GetSRegHi(rl_src1.s_reg_low), displacement + HIWORD_OFFSET, val_lo);
1658 GenImulMemImm(rs_r0, rl_src1.s_reg_low, displacement + LOWORD_OFFSET, val_hi);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001659 }
1660
1661 // ECX <- ECX + EAX (2H * 1L) + (1H * 2L)
buzbee091cc402014-03-31 10:14:40 -07001662 NewLIR2(kX86Add32RR, rs_r1.GetReg(), rs_r0.GetReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001663
1664 // EAX <- 2L
buzbee2700f7e2014-03-07 09:46:20 -08001665 LoadConstantNoClobber(rs_r0, val_lo);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001666
1667 // EDX:EAX <- 2L * 1L (double precision)
1668 if (src1_in_reg) {
buzbee2700f7e2014-03-07 09:46:20 -08001669 NewLIR1(kX86Mul32DaR, rl_src1.reg.GetLowReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001670 } else {
Ian Rogersb28c1c02014-11-08 11:21:21 -08001671 LIR *m = NewLIR2(kX86Mul32DaM, rs_rX86_SP_32.GetReg(), displacement + LOWORD_OFFSET);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001672 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
1673 true /* is_load */, true /* is_64bit */);
1674 }
1675
1676 // EDX <- EDX + ECX (add high words)
buzbee091cc402014-03-31 10:14:40 -07001677 NewLIR2(kX86Add32RR, rs_r2.GetReg(), rs_r1.GetReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001678
1679 // Result is EDX:EAX
buzbee091cc402014-03-31 10:14:40 -07001680 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
1681 RegStorage::MakeRegPair(rs_r0, rs_r2), INVALID_SREG, INVALID_SREG};
Mark Mendell4708dcd2014-01-22 09:05:18 -08001682 StoreValueWide(rl_dest, rl_result);
Andreas Gampec76c6142014-08-04 16:30:03 -07001683 return true;
1684 }
1685 return false;
1686}
1687
1688void X86Mir2Lir::GenMulLong(Instruction::Code, RegLocation rl_dest, RegLocation rl_src1,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07001689 RegLocation rl_src2, int flags) {
Andreas Gampec76c6142014-08-04 16:30:03 -07001690 if (rl_src1.is_const) {
1691 std::swap(rl_src1, rl_src2);
1692 }
1693
1694 if (rl_src2.is_const) {
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07001695 if (GenMulLongConst(rl_dest, rl_src1, mir_graph_->ConstantValueWide(rl_src2), flags)) {
Andreas Gampec76c6142014-08-04 16:30:03 -07001696 return;
1697 }
1698 }
1699
1700 // All memory accesses below reference dalvik regs.
1701 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
1702
1703 if (cu_->target64) {
1704 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
1705 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
1706 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
1707 if (rl_result.reg.GetReg() == rl_src1.reg.GetReg() &&
1708 rl_result.reg.GetReg() == rl_src2.reg.GetReg()) {
1709 NewLIR2(kX86Imul64RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
1710 } else if (rl_result.reg.GetReg() != rl_src1.reg.GetReg() &&
1711 rl_result.reg.GetReg() == rl_src2.reg.GetReg()) {
1712 NewLIR2(kX86Imul64RR, rl_result.reg.GetReg(), rl_src1.reg.GetReg());
1713 } else if (rl_result.reg.GetReg() == rl_src1.reg.GetReg() &&
1714 rl_result.reg.GetReg() != rl_src2.reg.GetReg()) {
1715 NewLIR2(kX86Imul64RR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
1716 } else {
1717 OpRegCopy(rl_result.reg, rl_src1.reg);
1718 NewLIR2(kX86Imul64RR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
1719 }
1720 StoreValueWide(rl_dest, rl_result);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001721 return;
1722 }
1723
Andreas Gampec76c6142014-08-04 16:30:03 -07001724 // Not multiplying by a constant. Do it the hard way
Mark Mendellde99bba2014-02-14 12:15:02 -08001725 // Check for V*V. We can eliminate a multiply in that case, as 2L*1H == 2H*1L.
1726 bool is_square = mir_graph_->SRegToVReg(rl_src1.s_reg_low) ==
1727 mir_graph_->SRegToVReg(rl_src2.s_reg_low);
1728
Maxim Kazantsev6dccdc22014-08-18 18:43:55 +07001729 // Prepare for explicit register usage.
1730 ExplicitTempRegisterLock(this, 3, &rs_r0, &rs_r1, &rs_r2);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001731 rl_src1 = UpdateLocWideTyped(rl_src1);
1732 rl_src2 = UpdateLocWideTyped(rl_src2);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001733
1734 // At this point, the VRs are in their home locations.
1735 bool src1_in_reg = rl_src1.location == kLocPhysReg;
1736 bool src2_in_reg = rl_src2.location == kLocPhysReg;
Ian Rogersb28c1c02014-11-08 11:21:21 -08001737 const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
Mark Mendell4708dcd2014-01-22 09:05:18 -08001738
1739 // ECX <- 1H
1740 if (src1_in_reg) {
buzbee091cc402014-03-31 10:14:40 -07001741 NewLIR2(kX86Mov32RR, rs_r1.GetReg(), rl_src1.reg.GetHighReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001742 } else {
Ian Rogersb28c1c02014-11-08 11:21:21 -08001743 LoadBaseDisp(rs_rSP, SRegOffset(rl_src1.s_reg_low) + HIWORD_OFFSET, rs_r1, k32,
Andreas Gampe3c12c512014-06-24 18:46:29 +00001744 kNotVolatile);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001745 }
1746
Mark Mendellde99bba2014-02-14 12:15:02 -08001747 if (is_square) {
1748 // Take advantage of the fact that the values are the same.
1749 // ECX <- ECX * 2L (1H * 2L)
1750 if (src2_in_reg) {
buzbee091cc402014-03-31 10:14:40 -07001751 NewLIR2(kX86Imul32RR, rs_r1.GetReg(), rl_src2.reg.GetLowReg());
Mark Mendellde99bba2014-02-14 12:15:02 -08001752 } else {
1753 int displacement = SRegOffset(rl_src2.s_reg_low);
Ian Rogersb28c1c02014-11-08 11:21:21 -08001754 LIR* m = NewLIR3(kX86Imul32RM, rs_r1.GetReg(), rs_rX86_SP_32.GetReg(),
buzbee091cc402014-03-31 10:14:40 -07001755 displacement + LOWORD_OFFSET);
Mark Mendellde99bba2014-02-14 12:15:02 -08001756 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
1757 true /* is_load */, true /* is_64bit */);
1758 }
Mark Mendell4708dcd2014-01-22 09:05:18 -08001759
Mark Mendellde99bba2014-02-14 12:15:02 -08001760 // ECX <- 2*ECX (2H * 1L) + (1H * 2L)
buzbee091cc402014-03-31 10:14:40 -07001761 NewLIR2(kX86Add32RR, rs_r1.GetReg(), rs_r1.GetReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001762 } else {
Mark Mendellde99bba2014-02-14 12:15:02 -08001763 // EAX <- 2H
1764 if (src2_in_reg) {
buzbee091cc402014-03-31 10:14:40 -07001765 NewLIR2(kX86Mov32RR, rs_r0.GetReg(), rl_src2.reg.GetHighReg());
Mark Mendellde99bba2014-02-14 12:15:02 -08001766 } else {
Ian Rogersb28c1c02014-11-08 11:21:21 -08001767 LoadBaseDisp(rs_rSP, SRegOffset(rl_src2.s_reg_low) + HIWORD_OFFSET, rs_r0, k32,
Andreas Gampe3c12c512014-06-24 18:46:29 +00001768 kNotVolatile);
Mark Mendellde99bba2014-02-14 12:15:02 -08001769 }
Mark Mendell4708dcd2014-01-22 09:05:18 -08001770
Mark Mendellde99bba2014-02-14 12:15:02 -08001771 // EAX <- EAX * 1L (2H * 1L)
1772 if (src1_in_reg) {
buzbee091cc402014-03-31 10:14:40 -07001773 NewLIR2(kX86Imul32RR, rs_r0.GetReg(), rl_src1.reg.GetLowReg());
Mark Mendellde99bba2014-02-14 12:15:02 -08001774 } else {
1775 int displacement = SRegOffset(rl_src1.s_reg_low);
Ian Rogersb28c1c02014-11-08 11:21:21 -08001776 LIR *m = NewLIR3(kX86Imul32RM, rs_r0.GetReg(), rs_rX86_SP_32.GetReg(),
buzbee091cc402014-03-31 10:14:40 -07001777 displacement + LOWORD_OFFSET);
Mark Mendellde99bba2014-02-14 12:15:02 -08001778 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
1779 true /* is_load */, true /* is_64bit */);
1780 }
Mark Mendell4708dcd2014-01-22 09:05:18 -08001781
Mark Mendellde99bba2014-02-14 12:15:02 -08001782 // ECX <- ECX * 2L (1H * 2L)
1783 if (src2_in_reg) {
buzbee091cc402014-03-31 10:14:40 -07001784 NewLIR2(kX86Imul32RR, rs_r1.GetReg(), rl_src2.reg.GetLowReg());
Mark Mendellde99bba2014-02-14 12:15:02 -08001785 } else {
1786 int displacement = SRegOffset(rl_src2.s_reg_low);
Ian Rogersb28c1c02014-11-08 11:21:21 -08001787 LIR *m = NewLIR3(kX86Imul32RM, rs_r1.GetReg(), rs_rX86_SP_32.GetReg(),
buzbee091cc402014-03-31 10:14:40 -07001788 displacement + LOWORD_OFFSET);
Mark Mendellde99bba2014-02-14 12:15:02 -08001789 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
1790 true /* is_load */, true /* is_64bit */);
1791 }
1792
1793 // ECX <- ECX + EAX (2H * 1L) + (1H * 2L)
buzbee091cc402014-03-31 10:14:40 -07001794 NewLIR2(kX86Add32RR, rs_r1.GetReg(), rs_r0.GetReg());
Mark Mendellde99bba2014-02-14 12:15:02 -08001795 }
Mark Mendell4708dcd2014-01-22 09:05:18 -08001796
1797 // EAX <- 2L
1798 if (src2_in_reg) {
buzbee091cc402014-03-31 10:14:40 -07001799 NewLIR2(kX86Mov32RR, rs_r0.GetReg(), rl_src2.reg.GetLowReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001800 } else {
Ian Rogersb28c1c02014-11-08 11:21:21 -08001801 LoadBaseDisp(rs_rSP, SRegOffset(rl_src2.s_reg_low) + LOWORD_OFFSET, rs_r0, k32,
Andreas Gampe3c12c512014-06-24 18:46:29 +00001802 kNotVolatile);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001803 }
1804
1805 // EDX:EAX <- 2L * 1L (double precision)
1806 if (src1_in_reg) {
buzbee2700f7e2014-03-07 09:46:20 -08001807 NewLIR1(kX86Mul32DaR, rl_src1.reg.GetLowReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001808 } else {
1809 int displacement = SRegOffset(rl_src1.s_reg_low);
Ian Rogersb28c1c02014-11-08 11:21:21 -08001810 LIR *m = NewLIR2(kX86Mul32DaM, rs_rX86_SP_32.GetReg(), displacement + LOWORD_OFFSET);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001811 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
1812 true /* is_load */, true /* is_64bit */);
1813 }
1814
1815 // EDX <- EDX + ECX (add high words)
buzbee091cc402014-03-31 10:14:40 -07001816 NewLIR2(kX86Add32RR, rs_r2.GetReg(), rs_r1.GetReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001817
1818 // Result is EDX:EAX
buzbee091cc402014-03-31 10:14:40 -07001819 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
buzbee2700f7e2014-03-07 09:46:20 -08001820 RegStorage::MakeRegPair(rs_r0, rs_r2), INVALID_SREG, INVALID_SREG};
Mark Mendell4708dcd2014-01-22 09:05:18 -08001821 StoreValueWide(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001822}
Mark Mendelle02d48f2014-01-15 11:19:23 -08001823
1824void X86Mir2Lir::GenLongRegOrMemOp(RegLocation rl_dest, RegLocation rl_src,
1825 Instruction::Code op) {
1826 DCHECK_EQ(rl_dest.location, kLocPhysReg);
1827 X86OpCode x86op = GetOpcode(op, rl_dest, rl_src, false);
1828 if (rl_src.location == kLocPhysReg) {
1829 // Both operands are in registers.
Serguei Katkovab5545f2014-03-25 10:51:15 +07001830 // But we must ensure that rl_src is in pair
Elena Sayapinadd644502014-07-01 18:39:52 +07001831 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -07001832 NewLIR2(x86op, rl_dest.reg.GetReg(), rl_src.reg.GetReg());
1833 } else {
1834 rl_src = LoadValueWide(rl_src, kCoreReg);
1835 if (rl_dest.reg.GetLowReg() == rl_src.reg.GetHighReg()) {
1836 // The registers are the same, so we would clobber it before the use.
1837 RegStorage temp_reg = AllocTemp();
1838 OpRegCopy(temp_reg, rl_dest.reg);
1839 rl_src.reg.SetHighReg(temp_reg.GetReg());
1840 }
1841 NewLIR2(x86op, rl_dest.reg.GetLowReg(), rl_src.reg.GetLowReg());
Mark Mendelle02d48f2014-01-15 11:19:23 -08001842
Chao-ying Fua0147762014-06-06 18:38:49 -07001843 x86op = GetOpcode(op, rl_dest, rl_src, true);
1844 NewLIR2(x86op, rl_dest.reg.GetHighReg(), rl_src.reg.GetHighReg());
Chao-ying Fua0147762014-06-06 18:38:49 -07001845 }
Mark Mendelle02d48f2014-01-15 11:19:23 -08001846 return;
1847 }
1848
1849 // RHS is in memory.
1850 DCHECK((rl_src.location == kLocDalvikFrame) ||
1851 (rl_src.location == kLocCompilerTemp));
Ian Rogersb28c1c02014-11-08 11:21:21 -08001852 int r_base = rs_rX86_SP_32.GetReg();
Mark Mendelle02d48f2014-01-15 11:19:23 -08001853 int displacement = SRegOffset(rl_src.s_reg_low);
1854
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001855 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
Andreas Gampeccc60262014-07-04 18:02:38 -07001856 LIR *lir = NewLIR3(x86op, cu_->target64 ? rl_dest.reg.GetReg() : rl_dest.reg.GetLowReg(),
1857 r_base, displacement + LOWORD_OFFSET);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001858 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
1859 true /* is_load */, true /* is64bit */);
Elena Sayapinadd644502014-07-01 18:39:52 +07001860 if (!cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -07001861 x86op = GetOpcode(op, rl_dest, rl_src, true);
1862 lir = NewLIR3(x86op, rl_dest.reg.GetHighReg(), r_base, displacement + HIWORD_OFFSET);
Chao-ying Fu7e399fd2014-06-10 18:11:11 -07001863 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
1864 true /* is_load */, true /* is64bit */);
Chao-ying Fua0147762014-06-06 18:38:49 -07001865 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07001866}
1867
Mark Mendelle02d48f2014-01-15 11:19:23 -08001868void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001869 rl_dest = UpdateLocWideTyped(rl_dest);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001870 if (rl_dest.location == kLocPhysReg) {
1871 // Ensure we are in a register pair
1872 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
1873
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001874 rl_src = UpdateLocWideTyped(rl_src);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001875 GenLongRegOrMemOp(rl_result, rl_src, op);
1876 StoreFinalValueWide(rl_dest, rl_result);
1877 return;
Alexei Zavjalovd8c3e362014-10-08 15:51:59 +07001878 } else if (!cu_->target64 && Intersects(rl_src, rl_dest)) {
1879 // Handle the case when src and dest are intersect.
1880 rl_src = LoadValueWide(rl_src, kCoreReg);
1881 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001882 rl_src = UpdateLocWideTyped(rl_src);
Alexei Zavjalovd8c3e362014-10-08 15:51:59 +07001883 GenLongRegOrMemOp(rl_result, rl_src, op);
1884 StoreFinalValueWide(rl_dest, rl_result);
1885 return;
Mark Mendelle02d48f2014-01-15 11:19:23 -08001886 }
1887
1888 // It wasn't in registers, so it better be in memory.
1889 DCHECK((rl_dest.location == kLocDalvikFrame) ||
1890 (rl_dest.location == kLocCompilerTemp));
1891 rl_src = LoadValueWide(rl_src, kCoreReg);
1892
1893 // Operate directly into memory.
1894 X86OpCode x86op = GetOpcode(op, rl_dest, rl_src, false);
Ian Rogersb28c1c02014-11-08 11:21:21 -08001895 int r_base = rs_rX86_SP_32.GetReg();
Mark Mendelle02d48f2014-01-15 11:19:23 -08001896 int displacement = SRegOffset(rl_dest.s_reg_low);
1897
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001898 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
Chao-ying Fua0147762014-06-06 18:38:49 -07001899 LIR *lir = NewLIR3(x86op, r_base, displacement + LOWORD_OFFSET,
Elena Sayapinadd644502014-07-01 18:39:52 +07001900 cu_->target64 ? rl_src.reg.GetReg() : rl_src.reg.GetLowReg());
Mark Mendelle02d48f2014-01-15 11:19:23 -08001901 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
Serguei Katkov217fe732014-03-27 14:41:56 +07001902 true /* is_load */, true /* is64bit */);
1903 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
Mark Mendelle02d48f2014-01-15 11:19:23 -08001904 false /* is_load */, true /* is64bit */);
Elena Sayapinadd644502014-07-01 18:39:52 +07001905 if (!cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -07001906 x86op = GetOpcode(op, rl_dest, rl_src, true);
1907 lir = NewLIR3(x86op, r_base, displacement + HIWORD_OFFSET, rl_src.reg.GetHighReg());
Chao-ying Fu7e399fd2014-06-10 18:11:11 -07001908 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
1909 true /* is_load */, true /* is64bit */);
1910 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
1911 false /* is_load */, true /* is64bit */);
Chao-ying Fua0147762014-06-06 18:38:49 -07001912 }
nikolay serdjuk6b9356c2014-11-13 18:15:23 +06001913
1914 int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low);
1915 int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
1916
1917 // If the left operand is in memory and the right operand is in a register
1918 // and both belong to the same dalvik register then we should clobber the
1919 // right one because it doesn't hold valid data anymore.
1920 if (v_src_reg == v_dst_reg) {
1921 Clobber(rl_src.reg);
1922 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07001923}
1924
Mark Mendelle02d48f2014-01-15 11:19:23 -08001925void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src1,
1926 RegLocation rl_src2, Instruction::Code op,
1927 bool is_commutative) {
1928 // Is this really a 2 operand operation?
1929 switch (op) {
1930 case Instruction::ADD_LONG_2ADDR:
1931 case Instruction::SUB_LONG_2ADDR:
1932 case Instruction::AND_LONG_2ADDR:
1933 case Instruction::OR_LONG_2ADDR:
1934 case Instruction::XOR_LONG_2ADDR:
Mark Mendelle87f9b52014-04-30 14:13:18 -04001935 if (GenerateTwoOperandInstructions()) {
1936 GenLongArith(rl_dest, rl_src2, op);
1937 return;
1938 }
1939 break;
1940
Mark Mendelle02d48f2014-01-15 11:19:23 -08001941 default:
1942 break;
1943 }
1944
1945 if (rl_dest.location == kLocPhysReg) {
1946 RegLocation rl_result = LoadValueWide(rl_src1, kCoreReg);
1947
1948 // We are about to clobber the LHS, so it needs to be a temp.
1949 rl_result = ForceTempWide(rl_result);
1950
1951 // Perform the operation using the RHS.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001952 rl_src2 = UpdateLocWideTyped(rl_src2);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001953 GenLongRegOrMemOp(rl_result, rl_src2, op);
1954
1955 // And now record that the result is in the temp.
1956 StoreFinalValueWide(rl_dest, rl_result);
1957 return;
1958 }
1959
1960 // It wasn't in registers, so it better be in memory.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001961 DCHECK((rl_dest.location == kLocDalvikFrame) || (rl_dest.location == kLocCompilerTemp));
1962 rl_src1 = UpdateLocWideTyped(rl_src1);
1963 rl_src2 = UpdateLocWideTyped(rl_src2);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001964
1965 // Get one of the source operands into temporary register.
1966 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
Elena Sayapinadd644502014-07-01 18:39:52 +07001967 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -07001968 if (IsTemp(rl_src1.reg)) {
1969 GenLongRegOrMemOp(rl_src1, rl_src2, op);
1970 } else if (is_commutative) {
1971 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
1972 // We need at least one of them to be a temporary.
1973 if (!IsTemp(rl_src2.reg)) {
1974 rl_src1 = ForceTempWide(rl_src1);
1975 GenLongRegOrMemOp(rl_src1, rl_src2, op);
1976 } else {
1977 GenLongRegOrMemOp(rl_src2, rl_src1, op);
1978 StoreFinalValueWide(rl_dest, rl_src2);
1979 return;
1980 }
1981 } else {
1982 // Need LHS to be the temp.
Mark Mendelle02d48f2014-01-15 11:19:23 -08001983 rl_src1 = ForceTempWide(rl_src1);
Yevgeny Rouban91b6ffa2014-03-07 14:35:44 +07001984 GenLongRegOrMemOp(rl_src1, rl_src2, op);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001985 }
Mark Mendelle02d48f2014-01-15 11:19:23 -08001986 } else {
Chao-ying Fua0147762014-06-06 18:38:49 -07001987 if (IsTemp(rl_src1.reg.GetLow()) && IsTemp(rl_src1.reg.GetHigh())) {
1988 GenLongRegOrMemOp(rl_src1, rl_src2, op);
1989 } else if (is_commutative) {
1990 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
1991 // We need at least one of them to be a temporary.
1992 if (!(IsTemp(rl_src2.reg.GetLow()) && IsTemp(rl_src2.reg.GetHigh()))) {
1993 rl_src1 = ForceTempWide(rl_src1);
1994 GenLongRegOrMemOp(rl_src1, rl_src2, op);
1995 } else {
1996 GenLongRegOrMemOp(rl_src2, rl_src1, op);
1997 StoreFinalValueWide(rl_dest, rl_src2);
1998 return;
1999 }
2000 } else {
2001 // Need LHS to be the temp.
2002 rl_src1 = ForceTempWide(rl_src1);
2003 GenLongRegOrMemOp(rl_src1, rl_src2, op);
2004 }
Mark Mendelle02d48f2014-01-15 11:19:23 -08002005 }
2006
2007 StoreFinalValueWide(rl_dest, rl_src1);
Brian Carlstrom7940e442013-07-12 13:46:57 -07002008}
2009
Serban Constantinescued65c5e2014-05-22 15:10:18 +01002010void X86Mir2Lir::GenNotLong(RegLocation rl_dest, RegLocation rl_src) {
Elena Sayapinadd644502014-07-01 18:39:52 +07002011 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -07002012 rl_src = LoadValueWide(rl_src, kCoreReg);
2013 RegLocation rl_result;
2014 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
2015 OpRegCopy(rl_result.reg, rl_src.reg);
2016 OpReg(kOpNot, rl_result.reg);
2017 StoreValueWide(rl_dest, rl_result);
2018 } else {
2019 LOG(FATAL) << "Unexpected use GenNotLong()";
2020 }
Serban Constantinescued65c5e2014-05-22 15:10:18 +01002021}
2022
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +07002023void X86Mir2Lir::GenDivRemLongLit(RegLocation rl_dest, RegLocation rl_src,
2024 int64_t imm, bool is_div) {
2025 if (imm == 0) {
2026 GenDivZeroException();
2027 } else if (imm == 1) {
2028 if (is_div) {
2029 // x / 1 == x.
2030 StoreValueWide(rl_dest, rl_src);
2031 } else {
2032 // x % 1 == 0.
2033 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
2034 LoadConstantWide(rl_result.reg, 0);
2035 StoreValueWide(rl_dest, rl_result);
2036 }
2037 } else if (imm == -1) { // handle 0x8000000000000000 / -1 special case.
2038 if (is_div) {
2039 rl_src = LoadValueWide(rl_src, kCoreReg);
2040 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
2041 RegStorage rs_temp = AllocTempWide();
2042
2043 OpRegCopy(rl_result.reg, rl_src.reg);
2044 LoadConstantWide(rs_temp, 0x8000000000000000);
2045
2046 // If x == MIN_LONG, return MIN_LONG.
2047 OpRegReg(kOpCmp, rl_src.reg, rs_temp);
2048 LIR *minint_branch = NewLIR2(kX86Jcc8, 0, kX86CondEq);
2049
2050 // For x != MIN_LONG, x / -1 == -x.
2051 OpReg(kOpNeg, rl_result.reg);
2052
2053 minint_branch->target = NewLIR0(kPseudoTargetLabel);
2054 FreeTemp(rs_temp);
2055 StoreValueWide(rl_dest, rl_result);
2056 } else {
2057 // x % -1 == 0.
2058 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
2059 LoadConstantWide(rl_result.reg, 0);
2060 StoreValueWide(rl_dest, rl_result);
2061 }
2062 } else if (is_div && IsPowerOfTwo(std::abs(imm))) {
2063 // Division using shifting.
2064 rl_src = LoadValueWide(rl_src, kCoreReg);
2065 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
2066 if (IsSameReg(rl_result.reg, rl_src.reg)) {
2067 RegStorage rs_temp = AllocTypedTempWide(false, kCoreReg);
2068 rl_result.reg.SetReg(rs_temp.GetReg());
2069 }
2070 LoadConstantWide(rl_result.reg, std::abs(imm) - 1);
2071 OpRegReg(kOpAdd, rl_result.reg, rl_src.reg);
2072 NewLIR2(kX86Test64RR, rl_src.reg.GetReg(), rl_src.reg.GetReg());
2073 OpCondRegReg(kOpCmov, kCondPl, rl_result.reg, rl_src.reg);
Andreas Gampe7e499922015-01-06 08:28:12 -08002074 int shift_amount = CTZ(imm);
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +07002075 OpRegImm(kOpAsr, rl_result.reg, shift_amount);
2076 if (imm < 0) {
2077 OpReg(kOpNeg, rl_result.reg);
2078 }
2079 StoreValueWide(rl_dest, rl_result);
2080 } else {
2081 CHECK(imm <= -2 || imm >= 2);
2082
2083 FlushReg(rs_r0q);
2084 Clobber(rs_r0q);
2085 LockTemp(rs_r0q);
2086 FlushReg(rs_r2q);
2087 Clobber(rs_r2q);
2088 LockTemp(rs_r2q);
2089
Mark Mendell3a91f442014-09-02 12:44:24 -04002090 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
2091 is_div ? rs_r2q : rs_r0q, INVALID_SREG, INVALID_SREG};
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +07002092
2093 // Use H.S.Warren's Hacker's Delight Chapter 10 and
2094 // T,Grablund, P.L.Montogomery's Division by invariant integers using multiplication.
2095 int64_t magic;
2096 int shift;
2097 CalculateMagicAndShift(imm, magic, shift, true /* is_long */);
2098
2099 /*
2100 * For imm >= 2,
2101 * int(n/imm) = floor(n/imm) = floor(M*n/2^S), while n > 0
2102 * int(n/imm) = ceil(n/imm) = floor(M*n/2^S) +1, while n < 0.
2103 * For imm <= -2,
2104 * int(n/imm) = ceil(n/imm) = floor(M*n/2^S) +1 , while n > 0
2105 * int(n/imm) = floor(n/imm) = floor(M*n/2^S), while n < 0.
2106 * We implement this algorithm in the following way:
2107 * 1. multiply magic number m and numerator n, get the higher 64bit result in RDX
2108 * 2. if imm > 0 and magic < 0, add numerator to RDX
2109 * if imm < 0 and magic > 0, sub numerator from RDX
2110 * 3. if S !=0, SAR S bits for RDX
2111 * 4. add 1 to RDX if RDX < 0
2112 * 5. Thus, RDX is the quotient
2113 */
2114
Mark Mendell3a91f442014-09-02 12:44:24 -04002115 // RAX = magic.
2116 LoadConstantWide(rs_r0q, magic);
2117
2118 // Multiply by numerator.
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +07002119 RegStorage numerator_reg;
2120 if (!is_div || (imm > 0 && magic < 0) || (imm < 0 && magic > 0)) {
2121 // We will need the value later.
2122 rl_src = LoadValueWide(rl_src, kCoreReg);
2123 numerator_reg = rl_src.reg;
Mark Mendell3a91f442014-09-02 12:44:24 -04002124
2125 // RDX:RAX = magic * numerator.
2126 NewLIR1(kX86Imul64DaR, numerator_reg.GetReg());
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +07002127 } else {
Mark Mendell3a91f442014-09-02 12:44:24 -04002128 // Only need this once. Multiply directly from the value.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002129 rl_src = UpdateLocWideTyped(rl_src);
Mark Mendell3a91f442014-09-02 12:44:24 -04002130 if (rl_src.location != kLocPhysReg) {
2131 // Okay, we can do this from memory.
2132 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
2133 int displacement = SRegOffset(rl_src.s_reg_low);
2134 // RDX:RAX = magic * numerator.
Ian Rogersb28c1c02014-11-08 11:21:21 -08002135 LIR *m = NewLIR2(kX86Imul64DaM, rs_rX86_SP_32.GetReg(), displacement);
Mark Mendell3a91f442014-09-02 12:44:24 -04002136 AnnotateDalvikRegAccess(m, displacement >> 2,
2137 true /* is_load */, true /* is_64bit */);
2138 } else {
2139 // RDX:RAX = magic * numerator.
2140 NewLIR1(kX86Imul64DaR, rl_src.reg.GetReg());
2141 }
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +07002142 }
2143
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +07002144 if (imm > 0 && magic < 0) {
2145 // Add numerator to RDX.
2146 DCHECK(numerator_reg.Valid());
2147 OpRegReg(kOpAdd, rs_r2q, numerator_reg);
2148 } else if (imm < 0 && magic > 0) {
2149 DCHECK(numerator_reg.Valid());
2150 OpRegReg(kOpSub, rs_r2q, numerator_reg);
2151 }
2152
2153 // Do we need the shift?
2154 if (shift != 0) {
2155 // Shift RDX by 'shift' bits.
2156 OpRegImm(kOpAsr, rs_r2q, shift);
2157 }
2158
2159 // Move RDX to RAX.
2160 OpRegCopyWide(rs_r0q, rs_r2q);
2161
2162 // Move sign bit to bit 0, zeroing the rest.
2163 OpRegImm(kOpLsr, rs_r2q, 63);
2164
2165 // RDX = RDX + RAX.
2166 OpRegReg(kOpAdd, rs_r2q, rs_r0q);
2167
2168 // Quotient is in RDX.
2169 if (!is_div) {
2170 // We need to compute the remainder.
2171 // Remainder is divisor - (quotient * imm).
2172 DCHECK(numerator_reg.Valid());
2173 OpRegCopyWide(rs_r0q, numerator_reg);
2174
2175 // Imul doesn't support 64-bit imms.
2176 if (imm > std::numeric_limits<int32_t>::max() ||
2177 imm < std::numeric_limits<int32_t>::min()) {
2178 RegStorage rs_temp = AllocTempWide();
2179 LoadConstantWide(rs_temp, imm);
2180
2181 // RAX = numerator * imm.
2182 NewLIR2(kX86Imul64RR, rs_r2q.GetReg(), rs_temp.GetReg());
2183
2184 FreeTemp(rs_temp);
2185 } else {
2186 // RAX = numerator * imm.
2187 int short_imm = static_cast<int>(imm);
2188 NewLIR3(kX86Imul64RRI, rs_r2q.GetReg(), rs_r2q.GetReg(), short_imm);
2189 }
2190
Mark Mendell3a91f442014-09-02 12:44:24 -04002191 // RAX -= RDX.
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +07002192 OpRegReg(kOpSub, rs_r0q, rs_r2q);
2193
Mark Mendell3a91f442014-09-02 12:44:24 -04002194 // Result in RAX.
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +07002195 } else {
Mark Mendell3a91f442014-09-02 12:44:24 -04002196 // Result in RDX.
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +07002197 }
2198 StoreValueWide(rl_dest, rl_result);
2199 FreeTemp(rs_r0q);
2200 FreeTemp(rs_r2q);
2201 }
2202}
2203
Serban Constantinescued65c5e2014-05-22 15:10:18 +01002204void X86Mir2Lir::GenDivRemLong(Instruction::Code, RegLocation rl_dest, RegLocation rl_src1,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07002205 RegLocation rl_src2, bool is_div, int flags) {
Elena Sayapinadd644502014-07-01 18:39:52 +07002206 if (!cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -07002207 LOG(FATAL) << "Unexpected use GenDivRemLong()";
2208 return;
2209 }
2210
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +07002211 if (rl_src2.is_const) {
2212 DCHECK(rl_src2.wide);
2213 int64_t imm = mir_graph_->ConstantValueWide(rl_src2);
2214 GenDivRemLongLit(rl_dest, rl_src1, imm, is_div);
2215 return;
2216 }
2217
Chao-ying Fua0147762014-06-06 18:38:49 -07002218 // We have to use fixed registers, so flush all the temps.
Maxim Kazantsev6dccdc22014-08-18 18:43:55 +07002219 // Prepare for explicit register usage.
2220 ExplicitTempRegisterLock(this, 4, &rs_r0q, &rs_r1q, &rs_r2q, &rs_r6q);
Chao-ying Fua0147762014-06-06 18:38:49 -07002221
2222 // Load LHS into RAX.
2223 LoadValueDirectWideFixed(rl_src1, rs_r0q);
2224
2225 // Load RHS into RCX.
2226 LoadValueDirectWideFixed(rl_src2, rs_r1q);
2227
2228 // Copy LHS sign bit into RDX.
2229 NewLIR0(kx86Cqo64Da);
2230
2231 // Handle division by zero case.
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07002232 if ((flags & MIR_IGNORE_DIV_ZERO_CHECK) == 0) {
2233 GenDivZeroCheckWide(rs_r1q);
2234 }
Chao-ying Fua0147762014-06-06 18:38:49 -07002235
2236 // Have to catch 0x8000000000000000/-1 case, or we will get an exception!
2237 NewLIR2(kX86Cmp64RI8, rs_r1q.GetReg(), -1);
Maxim Kazantsev6dccdc22014-08-18 18:43:55 +07002238 LIR* minus_one_branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
Chao-ying Fua0147762014-06-06 18:38:49 -07002239
2240 // RHS is -1.
Dmitry Petrochenko3157f9a2014-06-18 19:11:41 +07002241 LoadConstantWide(rs_r6q, 0x8000000000000000);
2242 NewLIR2(kX86Cmp64RR, rs_r0q.GetReg(), rs_r6q.GetReg());
Alexei Zavjalov6bbf0962014-07-15 02:19:41 +07002243 LIR *minint_branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
Chao-ying Fua0147762014-06-06 18:38:49 -07002244
2245 // In 0x8000000000000000/-1 case.
2246 if (!is_div) {
2247 // For DIV, RAX is already right. For REM, we need RDX 0.
2248 NewLIR2(kX86Xor64RR, rs_r2q.GetReg(), rs_r2q.GetReg());
2249 }
2250 LIR* done = NewLIR1(kX86Jmp8, 0);
2251
2252 // Expected case.
2253 minus_one_branch->target = NewLIR0(kPseudoTargetLabel);
2254 minint_branch->target = minus_one_branch->target;
2255 NewLIR1(kX86Idivmod64DaR, rs_r1q.GetReg());
2256 done->target = NewLIR0(kPseudoTargetLabel);
2257
2258 // Result is in RAX for div and RDX for rem.
2259 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, rs_r0q, INVALID_SREG, INVALID_SREG};
2260 if (!is_div) {
2261 rl_result.reg.SetReg(r2q);
2262 }
2263
2264 StoreValueWide(rl_dest, rl_result);
Serban Constantinescued65c5e2014-05-22 15:10:18 +01002265}
2266
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07002267void X86Mir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
Mark Mendelle02d48f2014-01-15 11:19:23 -08002268 rl_src = LoadValueWide(rl_src, kCoreReg);
Chao-ying Fua0147762014-06-06 18:38:49 -07002269 RegLocation rl_result;
Elena Sayapinadd644502014-07-01 18:39:52 +07002270 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -07002271 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
2272 OpRegReg(kOpNeg, rl_result.reg, rl_src.reg);
2273 } else {
2274 rl_result = ForceTempWide(rl_src);
Chao-ying Fua0147762014-06-06 18:38:49 -07002275 OpRegReg(kOpNeg, rl_result.reg.GetLow(), rl_result.reg.GetLow()); // rLow = -rLow
2276 OpRegImm(kOpAdc, rl_result.reg.GetHigh(), 0); // rHigh = rHigh + CF
2277 OpRegReg(kOpNeg, rl_result.reg.GetHigh(), rl_result.reg.GetHigh()); // rHigh = -rHigh
Mark Mendelle02d48f2014-01-15 11:19:23 -08002278 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07002279 StoreValueWide(rl_dest, rl_result);
2280}
2281
buzbee091cc402014-03-31 10:14:40 -07002282void X86Mir2Lir::OpRegThreadMem(OpKind op, RegStorage r_dest, ThreadOffset<4> thread_offset) {
Andreas Gampe2f244e92014-05-08 03:35:25 -07002283 DCHECK_EQ(kX86, cu_->instruction_set);
2284 X86OpCode opcode = kX86Bkpt;
2285 switch (op) {
2286 case kOpCmp: opcode = kX86Cmp32RT; break;
2287 case kOpMov: opcode = kX86Mov32RT; break;
2288 default:
2289 LOG(FATAL) << "Bad opcode: " << op;
2290 break;
2291 }
2292 NewLIR2(opcode, r_dest.GetReg(), thread_offset.Int32Value());
2293}
2294
2295void X86Mir2Lir::OpRegThreadMem(OpKind op, RegStorage r_dest, ThreadOffset<8> thread_offset) {
2296 DCHECK_EQ(kX86_64, cu_->instruction_set);
Brian Carlstrom7940e442013-07-12 13:46:57 -07002297 X86OpCode opcode = kX86Bkpt;
Elena Sayapinadd644502014-07-01 18:39:52 +07002298 if (cu_->target64 && r_dest.Is64BitSolo()) {
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +07002299 switch (op) {
2300 case kOpCmp: opcode = kX86Cmp64RT; break;
2301 case kOpMov: opcode = kX86Mov64RT; break;
2302 default:
2303 LOG(FATAL) << "Bad opcode(OpRegThreadMem 64): " << op;
2304 break;
2305 }
2306 } else {
2307 switch (op) {
2308 case kOpCmp: opcode = kX86Cmp32RT; break;
2309 case kOpMov: opcode = kX86Mov32RT; break;
2310 default:
2311 LOG(FATAL) << "Bad opcode: " << op;
2312 break;
2313 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07002314 }
buzbee091cc402014-03-31 10:14:40 -07002315 NewLIR2(opcode, r_dest.GetReg(), thread_offset.Int32Value());
Brian Carlstrom7940e442013-07-12 13:46:57 -07002316}
2317
2318/*
2319 * Generate array load
2320 */
2321void X86Mir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
Ian Rogersa9a82542013-10-04 11:17:26 -07002322 RegLocation rl_index, RegLocation rl_dest, int scale) {
Mark Mendellca541342014-10-15 16:59:49 -04002323 RegisterClass reg_class = RegClassForFieldLoadStore(size, false);
Brian Carlstrom7940e442013-07-12 13:46:57 -07002324 int len_offset = mirror::Array::LengthOffset().Int32Value();
Brian Carlstrom7940e442013-07-12 13:46:57 -07002325 RegLocation rl_result;
buzbeea0cd2d72014-06-01 09:33:49 -07002326 rl_array = LoadValue(rl_array, kRefReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -07002327
Mark Mendell343adb52013-12-18 06:02:17 -08002328 int data_offset;
buzbee695d13a2014-04-19 13:32:20 -07002329 if (size == k64 || size == kDouble) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07002330 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
2331 } else {
2332 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
2333 }
2334
Mark Mendell343adb52013-12-18 06:02:17 -08002335 bool constant_index = rl_index.is_const;
2336 int32_t constant_index_value = 0;
2337 if (!constant_index) {
2338 rl_index = LoadValue(rl_index, kCoreReg);
2339 } else {
2340 constant_index_value = mir_graph_->ConstantValue(rl_index);
2341 // If index is constant, just fold it into the data offset
2342 data_offset += constant_index_value << scale;
2343 // treat as non array below
buzbee2700f7e2014-03-07 09:46:20 -08002344 rl_index.reg = RegStorage::InvalidReg();
Mark Mendell343adb52013-12-18 06:02:17 -08002345 }
2346
Brian Carlstrom7940e442013-07-12 13:46:57 -07002347 /* null object? */
buzbee2700f7e2014-03-07 09:46:20 -08002348 GenNullCheck(rl_array.reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -07002349
2350 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
Mark Mendell343adb52013-12-18 06:02:17 -08002351 if (constant_index) {
Mingyao Yang80365d92014-04-18 12:10:58 -07002352 GenArrayBoundsCheck(constant_index_value, rl_array.reg, len_offset);
Mark Mendell343adb52013-12-18 06:02:17 -08002353 } else {
Mingyao Yang80365d92014-04-18 12:10:58 -07002354 GenArrayBoundsCheck(rl_index.reg, rl_array.reg, len_offset);
Mark Mendell343adb52013-12-18 06:02:17 -08002355 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07002356 }
Mark Mendell343adb52013-12-18 06:02:17 -08002357 rl_result = EvalLoc(rl_dest, reg_class, true);
Vladimir Marko3bf7c602014-05-07 14:55:43 +01002358 LoadBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_result.reg, size);
buzbee695d13a2014-04-19 13:32:20 -07002359 if ((size == k64) || (size == kDouble)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07002360 StoreValueWide(rl_dest, rl_result);
2361 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -07002362 StoreValue(rl_dest, rl_result);
2363 }
2364}
2365
2366/*
2367 * Generate array store
2368 *
2369 */
2370void X86Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
Ian Rogersa9a82542013-10-04 11:17:26 -07002371 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
Mark Mendellca541342014-10-15 16:59:49 -04002372 RegisterClass reg_class = RegClassForFieldLoadStore(size, false);
Brian Carlstrom7940e442013-07-12 13:46:57 -07002373 int len_offset = mirror::Array::LengthOffset().Int32Value();
2374 int data_offset;
2375
buzbee695d13a2014-04-19 13:32:20 -07002376 if (size == k64 || size == kDouble) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07002377 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
2378 } else {
2379 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
2380 }
2381
buzbeea0cd2d72014-06-01 09:33:49 -07002382 rl_array = LoadValue(rl_array, kRefReg);
Mark Mendell343adb52013-12-18 06:02:17 -08002383 bool constant_index = rl_index.is_const;
2384 int32_t constant_index_value = 0;
2385 if (!constant_index) {
2386 rl_index = LoadValue(rl_index, kCoreReg);
2387 } else {
2388 // If index is constant, just fold it into the data offset
2389 constant_index_value = mir_graph_->ConstantValue(rl_index);
2390 data_offset += constant_index_value << scale;
2391 // treat as non array below
buzbee2700f7e2014-03-07 09:46:20 -08002392 rl_index.reg = RegStorage::InvalidReg();
Mark Mendell343adb52013-12-18 06:02:17 -08002393 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07002394
2395 /* null object? */
buzbee2700f7e2014-03-07 09:46:20 -08002396 GenNullCheck(rl_array.reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -07002397
2398 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
Mark Mendell343adb52013-12-18 06:02:17 -08002399 if (constant_index) {
Mingyao Yang80365d92014-04-18 12:10:58 -07002400 GenArrayBoundsCheck(constant_index_value, rl_array.reg, len_offset);
Mark Mendell343adb52013-12-18 06:02:17 -08002401 } else {
Mingyao Yang80365d92014-04-18 12:10:58 -07002402 GenArrayBoundsCheck(rl_index.reg, rl_array.reg, len_offset);
Mark Mendell343adb52013-12-18 06:02:17 -08002403 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07002404 }
buzbee695d13a2014-04-19 13:32:20 -07002405 if ((size == k64) || (size == kDouble)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07002406 rl_src = LoadValueWide(rl_src, reg_class);
2407 } else {
2408 rl_src = LoadValue(rl_src, reg_class);
2409 }
2410 // If the src reg can't be byte accessed, move it to a temp first.
Chao-ying Fu7e399fd2014-06-10 18:11:11 -07002411 if ((size == kSignedByte || size == kUnsignedByte) && !IsByteRegister(rl_src.reg)) {
buzbee2700f7e2014-03-07 09:46:20 -08002412 RegStorage temp = AllocTemp();
2413 OpRegCopy(temp, rl_src.reg);
Jean Christophe Beylerb5bce7c2014-07-25 12:32:18 -07002414 StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, temp, size, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -07002415 } else {
Jean Christophe Beylerb5bce7c2014-07-25 12:32:18 -07002416 StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_src.reg, size, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -07002417 }
Ian Rogersa9a82542013-10-04 11:17:26 -07002418 if (card_mark) {
Ian Rogers773aab12013-10-14 13:50:10 -07002419 // Free rl_index if its a temp. Ensures there are 2 free regs for card mark.
Mark Mendell343adb52013-12-18 06:02:17 -08002420 if (!constant_index) {
buzbee091cc402014-03-31 10:14:40 -07002421 FreeTemp(rl_index.reg);
Mark Mendell343adb52013-12-18 06:02:17 -08002422 }
Vladimir Marko743b98c2014-11-24 19:45:41 +00002423 MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -07002424 }
2425}
2426
Mark Mendell4708dcd2014-01-22 09:05:18 -08002427RegLocation X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07002428 RegLocation rl_src, int shift_amount, int flags) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002429 UNUSED(flags);
Mark Mendelle87f9b52014-04-30 14:13:18 -04002430 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Elena Sayapinadd644502014-07-01 18:39:52 +07002431 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -07002432 OpKind op = static_cast<OpKind>(0); /* Make gcc happy */
2433 switch (opcode) {
2434 case Instruction::SHL_LONG:
2435 case Instruction::SHL_LONG_2ADDR:
2436 op = kOpLsl;
2437 break;
2438 case Instruction::SHR_LONG:
2439 case Instruction::SHR_LONG_2ADDR:
2440 op = kOpAsr;
2441 break;
2442 case Instruction::USHR_LONG:
2443 case Instruction::USHR_LONG_2ADDR:
2444 op = kOpLsr;
2445 break;
2446 default:
2447 LOG(FATAL) << "Unexpected case";
2448 }
2449 OpRegRegImm(op, rl_result.reg, rl_src.reg, shift_amount);
2450 } else {
2451 switch (opcode) {
2452 case Instruction::SHL_LONG:
2453 case Instruction::SHL_LONG_2ADDR:
2454 DCHECK_NE(shift_amount, 1); // Prevent a double store from happening.
2455 if (shift_amount == 32) {
2456 OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetLow());
2457 LoadConstant(rl_result.reg.GetLow(), 0);
2458 } else if (shift_amount > 31) {
2459 OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetLow());
2460 NewLIR2(kX86Sal32RI, rl_result.reg.GetHighReg(), shift_amount - 32);
2461 LoadConstant(rl_result.reg.GetLow(), 0);
2462 } else {
Mark Mendellb9b9d662014-06-16 13:03:42 -04002463 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetLow());
Chao-ying Fua0147762014-06-06 18:38:49 -07002464 OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
2465 NewLIR3(kX86Shld32RRI, rl_result.reg.GetHighReg(), rl_result.reg.GetLowReg(),
2466 shift_amount);
2467 NewLIR2(kX86Sal32RI, rl_result.reg.GetLowReg(), shift_amount);
2468 }
2469 break;
2470 case Instruction::SHR_LONG:
2471 case Instruction::SHR_LONG_2ADDR:
2472 if (shift_amount == 32) {
2473 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetHigh());
2474 OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
2475 NewLIR2(kX86Sar32RI, rl_result.reg.GetHighReg(), 31);
2476 } else if (shift_amount > 31) {
2477 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetHigh());
2478 OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
2479 NewLIR2(kX86Sar32RI, rl_result.reg.GetLowReg(), shift_amount - 32);
2480 NewLIR2(kX86Sar32RI, rl_result.reg.GetHighReg(), 31);
2481 } else {
Mark Mendellb9b9d662014-06-16 13:03:42 -04002482 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetLow());
Chao-ying Fua0147762014-06-06 18:38:49 -07002483 OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
2484 NewLIR3(kX86Shrd32RRI, rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg(),
2485 shift_amount);
2486 NewLIR2(kX86Sar32RI, rl_result.reg.GetHighReg(), shift_amount);
2487 }
2488 break;
2489 case Instruction::USHR_LONG:
2490 case Instruction::USHR_LONG_2ADDR:
2491 if (shift_amount == 32) {
2492 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetHigh());
2493 LoadConstant(rl_result.reg.GetHigh(), 0);
2494 } else if (shift_amount > 31) {
2495 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetHigh());
2496 NewLIR2(kX86Shr32RI, rl_result.reg.GetLowReg(), shift_amount - 32);
2497 LoadConstant(rl_result.reg.GetHigh(), 0);
2498 } else {
Mark Mendellb9b9d662014-06-16 13:03:42 -04002499 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetLow());
Chao-ying Fua0147762014-06-06 18:38:49 -07002500 OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
2501 NewLIR3(kX86Shrd32RRI, rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg(),
2502 shift_amount);
2503 NewLIR2(kX86Shr32RI, rl_result.reg.GetHighReg(), shift_amount);
2504 }
2505 break;
2506 default:
2507 LOG(FATAL) << "Unexpected case";
2508 }
Mark Mendell4708dcd2014-01-22 09:05:18 -08002509 }
2510 return rl_result;
2511}
2512
Brian Carlstrom7940e442013-07-12 13:46:57 -07002513void X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07002514 RegLocation rl_src, RegLocation rl_shift, int flags) {
Mark Mendell4708dcd2014-01-22 09:05:18 -08002515 // Per spec, we only care about low 6 bits of shift amount.
2516 int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f;
2517 if (shift_amount == 0) {
2518 rl_src = LoadValueWide(rl_src, kCoreReg);
2519 StoreValueWide(rl_dest, rl_src);
2520 return;
2521 } else if (shift_amount == 1 &&
2522 (opcode == Instruction::SHL_LONG || opcode == Instruction::SHL_LONG_2ADDR)) {
2523 // Need to handle this here to avoid calling StoreValueWide twice.
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07002524 GenArithOpLong(Instruction::ADD_LONG, rl_dest, rl_src, rl_src, flags);
Mark Mendell4708dcd2014-01-22 09:05:18 -08002525 return;
2526 }
Alexei Zavjalovd8c3e362014-10-08 15:51:59 +07002527 if (PartiallyIntersects(rl_src, rl_dest)) {
Mark Mendell4708dcd2014-01-22 09:05:18 -08002528 GenShiftOpLong(opcode, rl_dest, rl_src, rl_shift);
2529 return;
2530 }
2531 rl_src = LoadValueWide(rl_src, kCoreReg);
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07002532 RegLocation rl_result = GenShiftImmOpLong(opcode, rl_dest, rl_src, shift_amount, flags);
Mark Mendell4708dcd2014-01-22 09:05:18 -08002533 StoreValueWide(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -07002534}
2535
2536void X86Mir2Lir::GenArithImmOpLong(Instruction::Code opcode,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07002537 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
2538 int flags) {
Chao-ying Fua0147762014-06-06 18:38:49 -07002539 bool isConstSuccess = false;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002540 switch (opcode) {
2541 case Instruction::ADD_LONG:
2542 case Instruction::AND_LONG:
2543 case Instruction::OR_LONG:
2544 case Instruction::XOR_LONG:
2545 if (rl_src2.is_const) {
Chao-ying Fua0147762014-06-06 18:38:49 -07002546 isConstSuccess = GenLongLongImm(rl_dest, rl_src1, rl_src2, opcode);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002547 } else {
2548 DCHECK(rl_src1.is_const);
Chao-ying Fua0147762014-06-06 18:38:49 -07002549 isConstSuccess = GenLongLongImm(rl_dest, rl_src2, rl_src1, opcode);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002550 }
2551 break;
2552 case Instruction::SUB_LONG:
2553 case Instruction::SUB_LONG_2ADDR:
2554 if (rl_src2.is_const) {
Chao-ying Fua0147762014-06-06 18:38:49 -07002555 isConstSuccess = GenLongLongImm(rl_dest, rl_src1, rl_src2, opcode);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002556 } else {
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07002557 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
Chao-ying Fua0147762014-06-06 18:38:49 -07002558 isConstSuccess = true;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002559 }
2560 break;
2561 case Instruction::ADD_LONG_2ADDR:
2562 case Instruction::OR_LONG_2ADDR:
2563 case Instruction::XOR_LONG_2ADDR:
2564 case Instruction::AND_LONG_2ADDR:
2565 if (rl_src2.is_const) {
Mark Mendelle87f9b52014-04-30 14:13:18 -04002566 if (GenerateTwoOperandInstructions()) {
Chao-ying Fua0147762014-06-06 18:38:49 -07002567 isConstSuccess = GenLongImm(rl_dest, rl_src2, opcode);
Mark Mendelle87f9b52014-04-30 14:13:18 -04002568 } else {
Chao-ying Fua0147762014-06-06 18:38:49 -07002569 isConstSuccess = GenLongLongImm(rl_dest, rl_src1, rl_src2, opcode);
Mark Mendelle87f9b52014-04-30 14:13:18 -04002570 }
Mark Mendelle02d48f2014-01-15 11:19:23 -08002571 } else {
2572 DCHECK(rl_src1.is_const);
Chao-ying Fua0147762014-06-06 18:38:49 -07002573 isConstSuccess = GenLongLongImm(rl_dest, rl_src2, rl_src1, opcode);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002574 }
2575 break;
2576 default:
Chao-ying Fua0147762014-06-06 18:38:49 -07002577 isConstSuccess = false;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002578 break;
2579 }
Chao-ying Fua0147762014-06-06 18:38:49 -07002580
2581 if (!isConstSuccess) {
2582 // Default - bail to non-const handler.
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07002583 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
Chao-ying Fua0147762014-06-06 18:38:49 -07002584 }
Mark Mendelle02d48f2014-01-15 11:19:23 -08002585}
2586
2587bool X86Mir2Lir::IsNoOp(Instruction::Code op, int32_t value) {
2588 switch (op) {
2589 case Instruction::AND_LONG_2ADDR:
2590 case Instruction::AND_LONG:
2591 return value == -1;
2592 case Instruction::OR_LONG:
2593 case Instruction::OR_LONG_2ADDR:
2594 case Instruction::XOR_LONG:
2595 case Instruction::XOR_LONG_2ADDR:
2596 return value == 0;
2597 default:
2598 return false;
2599 }
2600}
2601
2602X86OpCode X86Mir2Lir::GetOpcode(Instruction::Code op, RegLocation dest, RegLocation rhs,
2603 bool is_high_op) {
2604 bool rhs_in_mem = rhs.location != kLocPhysReg;
2605 bool dest_in_mem = dest.location != kLocPhysReg;
Elena Sayapinadd644502014-07-01 18:39:52 +07002606 bool is64Bit = cu_->target64;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002607 DCHECK(!rhs_in_mem || !dest_in_mem);
2608 switch (op) {
2609 case Instruction::ADD_LONG:
2610 case Instruction::ADD_LONG_2ADDR:
2611 if (dest_in_mem) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002612 return is64Bit ? kX86Add64MR : is_high_op ? kX86Adc32MR : kX86Add32MR;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002613 } else if (rhs_in_mem) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002614 return is64Bit ? kX86Add64RM : is_high_op ? kX86Adc32RM : kX86Add32RM;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002615 }
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002616 return is64Bit ? kX86Add64RR : is_high_op ? kX86Adc32RR : kX86Add32RR;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002617 case Instruction::SUB_LONG:
2618 case Instruction::SUB_LONG_2ADDR:
2619 if (dest_in_mem) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002620 return is64Bit ? kX86Sub64MR : is_high_op ? kX86Sbb32MR : kX86Sub32MR;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002621 } else if (rhs_in_mem) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002622 return is64Bit ? kX86Sub64RM : is_high_op ? kX86Sbb32RM : kX86Sub32RM;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002623 }
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002624 return is64Bit ? kX86Sub64RR : is_high_op ? kX86Sbb32RR : kX86Sub32RR;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002625 case Instruction::AND_LONG_2ADDR:
2626 case Instruction::AND_LONG:
2627 if (dest_in_mem) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002628 return is64Bit ? kX86And64MR : kX86And32MR;
2629 }
2630 if (is64Bit) {
2631 return rhs_in_mem ? kX86And64RM : kX86And64RR;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002632 }
2633 return rhs_in_mem ? kX86And32RM : kX86And32RR;
2634 case Instruction::OR_LONG:
2635 case Instruction::OR_LONG_2ADDR:
2636 if (dest_in_mem) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002637 return is64Bit ? kX86Or64MR : kX86Or32MR;
2638 }
2639 if (is64Bit) {
2640 return rhs_in_mem ? kX86Or64RM : kX86Or64RR;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002641 }
2642 return rhs_in_mem ? kX86Or32RM : kX86Or32RR;
2643 case Instruction::XOR_LONG:
2644 case Instruction::XOR_LONG_2ADDR:
2645 if (dest_in_mem) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002646 return is64Bit ? kX86Xor64MR : kX86Xor32MR;
2647 }
2648 if (is64Bit) {
2649 return rhs_in_mem ? kX86Xor64RM : kX86Xor64RR;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002650 }
2651 return rhs_in_mem ? kX86Xor32RM : kX86Xor32RR;
2652 default:
2653 LOG(FATAL) << "Unexpected opcode: " << op;
2654 return kX86Add32RR;
2655 }
2656}
2657
2658X86OpCode X86Mir2Lir::GetOpcode(Instruction::Code op, RegLocation loc, bool is_high_op,
2659 int32_t value) {
2660 bool in_mem = loc.location != kLocPhysReg;
Elena Sayapinadd644502014-07-01 18:39:52 +07002661 bool is64Bit = cu_->target64;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002662 bool byte_imm = IS_SIMM8(value);
buzbee091cc402014-03-31 10:14:40 -07002663 DCHECK(in_mem || !loc.reg.IsFloat());
Mark Mendelle02d48f2014-01-15 11:19:23 -08002664 switch (op) {
2665 case Instruction::ADD_LONG:
2666 case Instruction::ADD_LONG_2ADDR:
2667 if (byte_imm) {
2668 if (in_mem) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002669 return is64Bit ? kX86Add64MI8 : is_high_op ? kX86Adc32MI8 : kX86Add32MI8;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002670 }
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002671 return is64Bit ? kX86Add64RI8 : is_high_op ? kX86Adc32RI8 : kX86Add32RI8;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002672 }
2673 if (in_mem) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002674 return is64Bit ? kX86Add64MI : is_high_op ? kX86Adc32MI : kX86Add32MI;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002675 }
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002676 return is64Bit ? kX86Add64RI : is_high_op ? kX86Adc32RI : kX86Add32RI;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002677 case Instruction::SUB_LONG:
2678 case Instruction::SUB_LONG_2ADDR:
2679 if (byte_imm) {
2680 if (in_mem) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002681 return is64Bit ? kX86Sub64MI8 : is_high_op ? kX86Sbb32MI8 : kX86Sub32MI8;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002682 }
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002683 return is64Bit ? kX86Sub64RI8 : is_high_op ? kX86Sbb32RI8 : kX86Sub32RI8;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002684 }
2685 if (in_mem) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002686 return is64Bit ? kX86Sub64MI : is_high_op ? kX86Sbb32MI : kX86Sub32MI;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002687 }
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002688 return is64Bit ? kX86Sub64RI : is_high_op ? kX86Sbb32RI : kX86Sub32RI;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002689 case Instruction::AND_LONG_2ADDR:
2690 case Instruction::AND_LONG:
2691 if (byte_imm) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002692 if (is64Bit) {
2693 return in_mem ? kX86And64MI8 : kX86And64RI8;
2694 }
Mark Mendelle02d48f2014-01-15 11:19:23 -08002695 return in_mem ? kX86And32MI8 : kX86And32RI8;
2696 }
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002697 if (is64Bit) {
2698 return in_mem ? kX86And64MI : kX86And64RI;
2699 }
Mark Mendelle02d48f2014-01-15 11:19:23 -08002700 return in_mem ? kX86And32MI : kX86And32RI;
2701 case Instruction::OR_LONG:
2702 case Instruction::OR_LONG_2ADDR:
2703 if (byte_imm) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002704 if (is64Bit) {
2705 return in_mem ? kX86Or64MI8 : kX86Or64RI8;
2706 }
Mark Mendelle02d48f2014-01-15 11:19:23 -08002707 return in_mem ? kX86Or32MI8 : kX86Or32RI8;
2708 }
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002709 if (is64Bit) {
2710 return in_mem ? kX86Or64MI : kX86Or64RI;
2711 }
Mark Mendelle02d48f2014-01-15 11:19:23 -08002712 return in_mem ? kX86Or32MI : kX86Or32RI;
2713 case Instruction::XOR_LONG:
2714 case Instruction::XOR_LONG_2ADDR:
2715 if (byte_imm) {
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002716 if (is64Bit) {
2717 return in_mem ? kX86Xor64MI8 : kX86Xor64RI8;
2718 }
Mark Mendelle02d48f2014-01-15 11:19:23 -08002719 return in_mem ? kX86Xor32MI8 : kX86Xor32RI8;
2720 }
Chao-ying Fue0ccdc02014-06-06 17:32:37 -07002721 if (is64Bit) {
2722 return in_mem ? kX86Xor64MI : kX86Xor64RI;
2723 }
Mark Mendelle02d48f2014-01-15 11:19:23 -08002724 return in_mem ? kX86Xor32MI : kX86Xor32RI;
2725 default:
2726 LOG(FATAL) << "Unexpected opcode: " << op;
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002727 UNREACHABLE();
Mark Mendelle02d48f2014-01-15 11:19:23 -08002728 }
2729}
2730
Chao-ying Fua0147762014-06-06 18:38:49 -07002731bool X86Mir2Lir::GenLongImm(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op) {
Mark Mendelle02d48f2014-01-15 11:19:23 -08002732 DCHECK(rl_src.is_const);
2733 int64_t val = mir_graph_->ConstantValueWide(rl_src);
Chao-ying Fua0147762014-06-06 18:38:49 -07002734
Elena Sayapinadd644502014-07-01 18:39:52 +07002735 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -07002736 // We can do with imm only if it fits 32 bit
2737 if (val != (static_cast<int64_t>(static_cast<int32_t>(val)))) {
2738 return false;
2739 }
2740
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002741 rl_dest = UpdateLocWideTyped(rl_dest);
Chao-ying Fua0147762014-06-06 18:38:49 -07002742
2743 if ((rl_dest.location == kLocDalvikFrame) ||
2744 (rl_dest.location == kLocCompilerTemp)) {
Ian Rogersb28c1c02014-11-08 11:21:21 -08002745 int r_base = rs_rX86_SP_32.GetReg();
Chao-ying Fua0147762014-06-06 18:38:49 -07002746 int displacement = SRegOffset(rl_dest.s_reg_low);
2747
Vladimir Marko8dea81c2014-06-06 14:50:36 +01002748 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
Chao-ying Fua0147762014-06-06 18:38:49 -07002749 X86OpCode x86op = GetOpcode(op, rl_dest, false, val);
2750 LIR *lir = NewLIR3(x86op, r_base, displacement + LOWORD_OFFSET, val);
2751 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
2752 true /* is_load */, true /* is64bit */);
2753 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
2754 false /* is_load */, true /* is64bit */);
2755 return true;
2756 }
2757
2758 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
2759 DCHECK_EQ(rl_result.location, kLocPhysReg);
2760 DCHECK(!rl_result.reg.IsFloat());
2761
2762 X86OpCode x86op = GetOpcode(op, rl_result, false, val);
2763 NewLIR2(x86op, rl_result.reg.GetReg(), val);
2764
2765 StoreValueWide(rl_dest, rl_result);
2766 return true;
2767 }
2768
Mark Mendelle02d48f2014-01-15 11:19:23 -08002769 int32_t val_lo = Low32Bits(val);
2770 int32_t val_hi = High32Bits(val);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002771 rl_dest = UpdateLocWideTyped(rl_dest);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002772
2773 // Can we just do this into memory?
2774 if ((rl_dest.location == kLocDalvikFrame) ||
2775 (rl_dest.location == kLocCompilerTemp)) {
Ian Rogersb28c1c02014-11-08 11:21:21 -08002776 int r_base = rs_rX86_SP_32.GetReg();
Mark Mendelle02d48f2014-01-15 11:19:23 -08002777 int displacement = SRegOffset(rl_dest.s_reg_low);
2778
Vladimir Marko8dea81c2014-06-06 14:50:36 +01002779 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002780 if (!IsNoOp(op, val_lo)) {
2781 X86OpCode x86op = GetOpcode(op, rl_dest, false, val_lo);
buzbee2700f7e2014-03-07 09:46:20 -08002782 LIR *lir = NewLIR3(x86op, r_base, displacement + LOWORD_OFFSET, val_lo);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002783 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
Serguei Katkov217fe732014-03-27 14:41:56 +07002784 true /* is_load */, true /* is64bit */);
2785 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
Mark Mendelle02d48f2014-01-15 11:19:23 -08002786 false /* is_load */, true /* is64bit */);
2787 }
2788 if (!IsNoOp(op, val_hi)) {
2789 X86OpCode x86op = GetOpcode(op, rl_dest, true, val_hi);
buzbee2700f7e2014-03-07 09:46:20 -08002790 LIR *lir = NewLIR3(x86op, r_base, displacement + HIWORD_OFFSET, val_hi);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002791 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
Serguei Katkov217fe732014-03-27 14:41:56 +07002792 true /* is_load */, true /* is64bit */);
2793 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
Mark Mendelle02d48f2014-01-15 11:19:23 -08002794 false /* is_load */, true /* is64bit */);
2795 }
Chao-ying Fua0147762014-06-06 18:38:49 -07002796 return true;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002797 }
2798
2799 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
2800 DCHECK_EQ(rl_result.location, kLocPhysReg);
buzbee091cc402014-03-31 10:14:40 -07002801 DCHECK(!rl_result.reg.IsFloat());
Mark Mendelle02d48f2014-01-15 11:19:23 -08002802
2803 if (!IsNoOp(op, val_lo)) {
2804 X86OpCode x86op = GetOpcode(op, rl_result, false, val_lo);
buzbee2700f7e2014-03-07 09:46:20 -08002805 NewLIR2(x86op, rl_result.reg.GetLowReg(), val_lo);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002806 }
2807 if (!IsNoOp(op, val_hi)) {
2808 X86OpCode x86op = GetOpcode(op, rl_result, true, val_hi);
Bill Buzbee00e1ec62014-02-27 23:44:13 +00002809 NewLIR2(x86op, rl_result.reg.GetHighReg(), val_hi);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002810 }
2811 StoreValueWide(rl_dest, rl_result);
Chao-ying Fua0147762014-06-06 18:38:49 -07002812 return true;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002813}
2814
Chao-ying Fua0147762014-06-06 18:38:49 -07002815bool X86Mir2Lir::GenLongLongImm(RegLocation rl_dest, RegLocation rl_src1,
Mark Mendelle02d48f2014-01-15 11:19:23 -08002816 RegLocation rl_src2, Instruction::Code op) {
2817 DCHECK(rl_src2.is_const);
2818 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
Chao-ying Fua0147762014-06-06 18:38:49 -07002819
Elena Sayapinadd644502014-07-01 18:39:52 +07002820 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -07002821 // We can do with imm only if it fits 32 bit
2822 if (val != (static_cast<int64_t>(static_cast<int32_t>(val)))) {
2823 return false;
2824 }
2825 if (rl_dest.location == kLocPhysReg &&
2826 rl_src1.location == kLocPhysReg && !rl_dest.reg.IsFloat()) {
2827 X86OpCode x86op = GetOpcode(op, rl_dest, false, val);
Dmitry Petrochenko3157f9a2014-06-18 19:11:41 +07002828 OpRegCopy(rl_dest.reg, rl_src1.reg);
Chao-ying Fua0147762014-06-06 18:38:49 -07002829 NewLIR2(x86op, rl_dest.reg.GetReg(), val);
2830 StoreFinalValueWide(rl_dest, rl_dest);
2831 return true;
2832 }
2833
2834 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
2835 // We need the values to be in a temporary
2836 RegLocation rl_result = ForceTempWide(rl_src1);
2837
2838 X86OpCode x86op = GetOpcode(op, rl_result, false, val);
2839 NewLIR2(x86op, rl_result.reg.GetReg(), val);
2840
2841 StoreFinalValueWide(rl_dest, rl_result);
2842 return true;
2843 }
2844
Mark Mendelle02d48f2014-01-15 11:19:23 -08002845 int32_t val_lo = Low32Bits(val);
2846 int32_t val_hi = High32Bits(val);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002847 rl_dest = UpdateLocWideTyped(rl_dest);
2848 rl_src1 = UpdateLocWideTyped(rl_src1);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002849
2850 // Can we do this directly into the destination registers?
2851 if (rl_dest.location == kLocPhysReg && rl_src1.location == kLocPhysReg &&
buzbee2700f7e2014-03-07 09:46:20 -08002852 rl_dest.reg.GetLowReg() == rl_src1.reg.GetLowReg() &&
buzbee091cc402014-03-31 10:14:40 -07002853 rl_dest.reg.GetHighReg() == rl_src1.reg.GetHighReg() && !rl_dest.reg.IsFloat()) {
Mark Mendelle02d48f2014-01-15 11:19:23 -08002854 if (!IsNoOp(op, val_lo)) {
2855 X86OpCode x86op = GetOpcode(op, rl_dest, false, val_lo);
buzbee2700f7e2014-03-07 09:46:20 -08002856 NewLIR2(x86op, rl_dest.reg.GetLowReg(), val_lo);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002857 }
2858 if (!IsNoOp(op, val_hi)) {
2859 X86OpCode x86op = GetOpcode(op, rl_dest, true, val_hi);
Bill Buzbee00e1ec62014-02-27 23:44:13 +00002860 NewLIR2(x86op, rl_dest.reg.GetHighReg(), val_hi);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002861 }
Maxim Kazantsev653f2bf2014-02-13 15:11:17 +07002862
2863 StoreFinalValueWide(rl_dest, rl_dest);
Chao-ying Fua0147762014-06-06 18:38:49 -07002864 return true;
Mark Mendelle02d48f2014-01-15 11:19:23 -08002865 }
2866
2867 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
2868 DCHECK_EQ(rl_src1.location, kLocPhysReg);
2869
2870 // We need the values to be in a temporary
2871 RegLocation rl_result = ForceTempWide(rl_src1);
2872 if (!IsNoOp(op, val_lo)) {
2873 X86OpCode x86op = GetOpcode(op, rl_result, false, val_lo);
buzbee2700f7e2014-03-07 09:46:20 -08002874 NewLIR2(x86op, rl_result.reg.GetLowReg(), val_lo);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002875 }
2876 if (!IsNoOp(op, val_hi)) {
2877 X86OpCode x86op = GetOpcode(op, rl_result, true, val_hi);
Bill Buzbee00e1ec62014-02-27 23:44:13 +00002878 NewLIR2(x86op, rl_result.reg.GetHighReg(), val_hi);
Mark Mendelle02d48f2014-01-15 11:19:23 -08002879 }
2880
2881 StoreFinalValueWide(rl_dest, rl_result);
Chao-ying Fua0147762014-06-06 18:38:49 -07002882 return true;
Brian Carlstrom7940e442013-07-12 13:46:57 -07002883}
2884
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08002885// For final classes there are no sub-classes to check and so we can answer the instance-of
2886// question with simple comparisons. Use compares to memory and SETEQ to optimize for x86.
2887void X86Mir2Lir::GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx,
2888 RegLocation rl_dest, RegLocation rl_src) {
buzbeea0cd2d72014-06-01 09:33:49 -07002889 RegLocation object = LoadValue(rl_src, kRefReg);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08002890 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08002891 RegStorage result_reg = rl_result.reg;
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08002892
Chao-ying Fu7e399fd2014-06-10 18:11:11 -07002893 // For 32-bit, SETcc only works with EAX..EDX.
Chao-ying Fua77ee512014-07-01 17:43:41 -07002894 RegStorage object_32reg = object.reg.Is64Bit() ? As32BitReg(object.reg) : object.reg;
Dmitry Petrochenko407f5c12014-07-01 01:21:38 +07002895 if (result_reg.GetRegNum() == object_32reg.GetRegNum() || !IsByteRegister(result_reg)) {
Mark Mendelle87f9b52014-04-30 14:13:18 -04002896 result_reg = AllocateByteRegister();
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08002897 }
2898
2899 // Assume that there is no match.
2900 LoadConstant(result_reg, 0);
buzbee2700f7e2014-03-07 09:46:20 -08002901 LIR* null_branchover = OpCmpImmBranch(kCondEq, object.reg, 0, NULL);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08002902
Mark Mendellade54a22014-06-09 12:49:55 -04002903 // We will use this register to compare to memory below.
2904 // References are 32 bit in memory, and 64 bit in registers (in 64 bit mode).
2905 // For this reason, force allocation of a 32 bit register to use, so that the
2906 // compare to memory will be done using a 32 bit comparision.
2907 // The LoadRefDisp(s) below will work normally, even in 64 bit mode.
2908 RegStorage check_class = AllocTemp();
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08002909
2910 // If Method* is already in a register, we can save a copy.
2911 RegLocation rl_method = mir_graph_->GetMethodLoc();
Andreas Gampeccc60262014-07-04 18:02:38 -07002912 int32_t offset_of_type = mirror::Array::DataOffset(
2913 sizeof(mirror::HeapReference<mirror::Class*>)).Int32Value() +
2914 (sizeof(mirror::HeapReference<mirror::Class*>) * type_idx);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08002915
2916 if (rl_method.location == kLocPhysReg) {
2917 if (use_declaring_class) {
buzbee695d13a2014-04-19 13:32:20 -07002918 LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
Andreas Gampe3c12c512014-06-24 18:46:29 +00002919 check_class, kNotVolatile);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08002920 } else {
buzbee695d13a2014-04-19 13:32:20 -07002921 LoadRefDisp(rl_method.reg, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
Andreas Gampe3c12c512014-06-24 18:46:29 +00002922 check_class, kNotVolatile);
2923 LoadRefDisp(check_class, offset_of_type, check_class, kNotVolatile);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08002924 }
2925 } else {
2926 LoadCurrMethodDirect(check_class);
2927 if (use_declaring_class) {
buzbee695d13a2014-04-19 13:32:20 -07002928 LoadRefDisp(check_class, mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
Andreas Gampe3c12c512014-06-24 18:46:29 +00002929 check_class, kNotVolatile);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08002930 } else {
buzbee695d13a2014-04-19 13:32:20 -07002931 LoadRefDisp(check_class, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
Andreas Gampe3c12c512014-06-24 18:46:29 +00002932 check_class, kNotVolatile);
2933 LoadRefDisp(check_class, offset_of_type, check_class, kNotVolatile);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08002934 }
2935 }
2936
2937 // Compare the computed class to the class in the object.
2938 DCHECK_EQ(object.location, kLocPhysReg);
buzbee2700f7e2014-03-07 09:46:20 -08002939 OpRegMem(kOpCmp, check_class, object.reg, mirror::Object::ClassOffset().Int32Value());
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08002940
2941 // Set the low byte of the result to 0 or 1 from the compare condition code.
buzbee2700f7e2014-03-07 09:46:20 -08002942 NewLIR2(kX86Set8R, result_reg.GetReg(), kX86CondEq);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08002943
2944 LIR* target = NewLIR0(kPseudoTargetLabel);
2945 null_branchover->target = target;
2946 FreeTemp(check_class);
2947 if (IsTemp(result_reg)) {
buzbee2700f7e2014-03-07 09:46:20 -08002948 OpRegCopy(rl_result.reg, result_reg);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08002949 FreeTemp(result_reg);
2950 }
2951 StoreValue(rl_dest, rl_result);
2952}
2953
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002954void X86Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07002955 RegLocation rl_lhs, RegLocation rl_rhs, int flags) {
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002956 OpKind op = kOpBkpt;
2957 bool is_div_rem = false;
2958 bool unary = false;
2959 bool shift_op = false;
2960 bool is_two_addr = false;
2961 RegLocation rl_result;
2962 switch (opcode) {
2963 case Instruction::NEG_INT:
2964 op = kOpNeg;
2965 unary = true;
2966 break;
2967 case Instruction::NOT_INT:
2968 op = kOpMvn;
2969 unary = true;
2970 break;
2971 case Instruction::ADD_INT_2ADDR:
2972 is_two_addr = true;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002973 FALLTHROUGH_INTENDED;
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002974 case Instruction::ADD_INT:
2975 op = kOpAdd;
2976 break;
2977 case Instruction::SUB_INT_2ADDR:
2978 is_two_addr = true;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002979 FALLTHROUGH_INTENDED;
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002980 case Instruction::SUB_INT:
2981 op = kOpSub;
2982 break;
2983 case Instruction::MUL_INT_2ADDR:
2984 is_two_addr = true;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002985 FALLTHROUGH_INTENDED;
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002986 case Instruction::MUL_INT:
2987 op = kOpMul;
2988 break;
2989 case Instruction::DIV_INT_2ADDR:
2990 is_two_addr = true;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002991 FALLTHROUGH_INTENDED;
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002992 case Instruction::DIV_INT:
2993 op = kOpDiv;
2994 is_div_rem = true;
2995 break;
2996 /* NOTE: returns in kArg1 */
2997 case Instruction::REM_INT_2ADDR:
2998 is_two_addr = true;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002999 FALLTHROUGH_INTENDED;
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003000 case Instruction::REM_INT:
3001 op = kOpRem;
3002 is_div_rem = true;
3003 break;
3004 case Instruction::AND_INT_2ADDR:
3005 is_two_addr = true;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003006 FALLTHROUGH_INTENDED;
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003007 case Instruction::AND_INT:
3008 op = kOpAnd;
3009 break;
3010 case Instruction::OR_INT_2ADDR:
3011 is_two_addr = true;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003012 FALLTHROUGH_INTENDED;
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003013 case Instruction::OR_INT:
3014 op = kOpOr;
3015 break;
3016 case Instruction::XOR_INT_2ADDR:
3017 is_two_addr = true;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003018 FALLTHROUGH_INTENDED;
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003019 case Instruction::XOR_INT:
3020 op = kOpXor;
3021 break;
3022 case Instruction::SHL_INT_2ADDR:
3023 is_two_addr = true;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003024 FALLTHROUGH_INTENDED;
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003025 case Instruction::SHL_INT:
3026 shift_op = true;
3027 op = kOpLsl;
3028 break;
3029 case Instruction::SHR_INT_2ADDR:
3030 is_two_addr = true;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003031 FALLTHROUGH_INTENDED;
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003032 case Instruction::SHR_INT:
3033 shift_op = true;
3034 op = kOpAsr;
3035 break;
3036 case Instruction::USHR_INT_2ADDR:
3037 is_two_addr = true;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003038 FALLTHROUGH_INTENDED;
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003039 case Instruction::USHR_INT:
3040 shift_op = true;
3041 op = kOpLsr;
3042 break;
3043 default:
3044 LOG(FATAL) << "Invalid word arith op: " << opcode;
3045 }
3046
Mark Mendelle87f9b52014-04-30 14:13:18 -04003047 // Can we convert to a two address instruction?
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003048 if (!is_two_addr &&
3049 (mir_graph_->SRegToVReg(rl_dest.s_reg_low) ==
3050 mir_graph_->SRegToVReg(rl_lhs.s_reg_low))) {
Mark Mendelle87f9b52014-04-30 14:13:18 -04003051 is_two_addr = true;
3052 }
3053
3054 if (!GenerateTwoOperandInstructions()) {
3055 is_two_addr = false;
3056 }
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003057
3058 // Get the div/rem stuff out of the way.
3059 if (is_div_rem) {
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -07003060 rl_result = GenDivRem(rl_dest, rl_lhs, rl_rhs, op == kOpDiv, flags);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003061 StoreValue(rl_dest, rl_result);
3062 return;
3063 }
3064
Vladimir Marko8dea81c2014-06-06 14:50:36 +01003065 // If we generate any memory access below, it will reference a dalvik reg.
3066 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
3067
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003068 if (unary) {
3069 rl_lhs = LoadValue(rl_lhs, kCoreReg);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003070 rl_result = UpdateLocTyped(rl_dest);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003071 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08003072 OpRegReg(op, rl_result.reg, rl_lhs.reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003073 } else {
3074 if (shift_op) {
3075 // X86 doesn't require masking and must use ECX.
Andreas Gampeccc60262014-07-04 18:02:38 -07003076 RegStorage t_reg = TargetReg(kCount, kNotWide); // rCX
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003077 LoadValueDirectFixed(rl_rhs, t_reg);
3078 if (is_two_addr) {
3079 // Can we do this directly into memory?
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003080 rl_result = UpdateLocTyped(rl_dest);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003081 if (rl_result.location != kLocPhysReg) {
3082 // Okay, we can do this into memory
buzbee2700f7e2014-03-07 09:46:20 -08003083 OpMemReg(op, rl_result, t_reg.GetReg());
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003084 FreeTemp(t_reg);
3085 return;
buzbee091cc402014-03-31 10:14:40 -07003086 } else if (!rl_result.reg.IsFloat()) {
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003087 // Can do this directly into the result register
buzbee2700f7e2014-03-07 09:46:20 -08003088 OpRegReg(op, rl_result.reg, t_reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003089 FreeTemp(t_reg);
3090 StoreFinalValue(rl_dest, rl_result);
3091 return;
3092 }
3093 }
3094 // Three address form, or we can't do directly.
3095 rl_lhs = LoadValue(rl_lhs, kCoreReg);
3096 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08003097 OpRegRegReg(op, rl_result.reg, rl_lhs.reg, t_reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003098 FreeTemp(t_reg);
3099 } else {
3100 // Multiply is 3 operand only (sort of).
3101 if (is_two_addr && op != kOpMul) {
3102 // Can we do this directly into memory?
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003103 rl_result = UpdateLocTyped(rl_dest);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003104 if (rl_result.location == kLocPhysReg) {
Serguei Katkov366f8ae2014-04-15 16:55:26 +07003105 // Ensure res is in a core reg
3106 rl_result = EvalLoc(rl_dest, kCoreReg, true);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003107 // Can we do this from memory directly?
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003108 rl_rhs = UpdateLocTyped(rl_rhs);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003109 if (rl_rhs.location != kLocPhysReg) {
buzbee2700f7e2014-03-07 09:46:20 -08003110 OpRegMem(op, rl_result.reg, rl_rhs);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003111 StoreFinalValue(rl_dest, rl_result);
3112 return;
buzbee091cc402014-03-31 10:14:40 -07003113 } else if (!rl_rhs.reg.IsFloat()) {
buzbee2700f7e2014-03-07 09:46:20 -08003114 OpRegReg(op, rl_result.reg, rl_rhs.reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003115 StoreFinalValue(rl_dest, rl_result);
3116 return;
3117 }
3118 }
3119 rl_rhs = LoadValue(rl_rhs, kCoreReg);
Serguei Katkovd293fb42014-05-19 15:45:42 +07003120 // It might happen rl_rhs and rl_dest are the same VR
3121 // in this case rl_dest is in reg after LoadValue while
3122 // rl_result is not updated yet, so do this
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003123 rl_result = UpdateLocTyped(rl_dest);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003124 if (rl_result.location != kLocPhysReg) {
3125 // Okay, we can do this into memory.
Bill Buzbee00e1ec62014-02-27 23:44:13 +00003126 OpMemReg(op, rl_result, rl_rhs.reg.GetReg());
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003127 return;
buzbee091cc402014-03-31 10:14:40 -07003128 } else if (!rl_result.reg.IsFloat()) {
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003129 // Can do this directly into the result register.
buzbee2700f7e2014-03-07 09:46:20 -08003130 OpRegReg(op, rl_result.reg, rl_rhs.reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003131 StoreFinalValue(rl_dest, rl_result);
3132 return;
3133 } else {
3134 rl_lhs = LoadValue(rl_lhs, kCoreReg);
3135 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08003136 OpRegRegReg(op, rl_result.reg, rl_lhs.reg, rl_rhs.reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003137 }
3138 } else {
3139 // Try to use reg/memory instructions.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003140 rl_lhs = UpdateLocTyped(rl_lhs);
3141 rl_rhs = UpdateLocTyped(rl_rhs);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003142 // We can't optimize with FP registers.
3143 if (!IsOperationSafeWithoutTemps(rl_lhs, rl_rhs)) {
3144 // Something is difficult, so fall back to the standard case.
3145 rl_lhs = LoadValue(rl_lhs, kCoreReg);
3146 rl_rhs = LoadValue(rl_rhs, kCoreReg);
3147 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08003148 OpRegRegReg(op, rl_result.reg, rl_lhs.reg, rl_rhs.reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003149 } else {
3150 // We can optimize by moving to result and using memory operands.
3151 if (rl_rhs.location != kLocPhysReg) {
3152 // Force LHS into result.
Serguei Katkov66da1362014-03-14 13:33:33 +07003153 // We should be careful with order here
3154 // If rl_dest and rl_lhs points to the same VR we should load first
3155 // If the are different we should find a register first for dest
Chao-ying Fua0147762014-06-06 18:38:49 -07003156 if (mir_graph_->SRegToVReg(rl_dest.s_reg_low) ==
3157 mir_graph_->SRegToVReg(rl_lhs.s_reg_low)) {
Serguei Katkov66da1362014-03-14 13:33:33 +07003158 rl_lhs = LoadValue(rl_lhs, kCoreReg);
3159 rl_result = EvalLoc(rl_dest, kCoreReg, true);
Mark Mendelle87f9b52014-04-30 14:13:18 -04003160 // No-op if these are the same.
3161 OpRegCopy(rl_result.reg, rl_lhs.reg);
Serguei Katkov66da1362014-03-14 13:33:33 +07003162 } else {
3163 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08003164 LoadValueDirect(rl_lhs, rl_result.reg);
Serguei Katkov66da1362014-03-14 13:33:33 +07003165 }
buzbee2700f7e2014-03-07 09:46:20 -08003166 OpRegMem(op, rl_result.reg, rl_rhs);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003167 } else if (rl_lhs.location != kLocPhysReg) {
3168 // RHS is in a register; LHS is in memory.
3169 if (op != kOpSub) {
3170 // Force RHS into result and operate on memory.
3171 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08003172 OpRegCopy(rl_result.reg, rl_rhs.reg);
3173 OpRegMem(op, rl_result.reg, rl_lhs);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003174 } else {
3175 // Subtraction isn't commutative.
3176 rl_lhs = LoadValue(rl_lhs, kCoreReg);
3177 rl_rhs = LoadValue(rl_rhs, kCoreReg);
3178 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08003179 OpRegRegReg(op, rl_result.reg, rl_lhs.reg, rl_rhs.reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003180 }
3181 } else {
3182 // Both are in registers.
3183 rl_lhs = LoadValue(rl_lhs, kCoreReg);
3184 rl_rhs = LoadValue(rl_rhs, kCoreReg);
3185 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08003186 OpRegRegReg(op, rl_result.reg, rl_lhs.reg, rl_rhs.reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003187 }
3188 }
3189 }
3190 }
3191 }
3192 StoreValue(rl_dest, rl_result);
3193}
3194
3195bool X86Mir2Lir::IsOperationSafeWithoutTemps(RegLocation rl_lhs, RegLocation rl_rhs) {
3196 // If we have non-core registers, then we can't do good things.
buzbee091cc402014-03-31 10:14:40 -07003197 if (rl_lhs.location == kLocPhysReg && rl_lhs.reg.IsFloat()) {
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003198 return false;
3199 }
buzbee091cc402014-03-31 10:14:40 -07003200 if (rl_rhs.location == kLocPhysReg && rl_rhs.reg.IsFloat()) {
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08003201 return false;
3202 }
3203
3204 // Everything will be fine :-).
3205 return true;
3206}
Chao-ying Fua0147762014-06-06 18:38:49 -07003207
3208void X86Mir2Lir::GenIntToLong(RegLocation rl_dest, RegLocation rl_src) {
Elena Sayapinadd644502014-07-01 18:39:52 +07003209 if (!cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -07003210 Mir2Lir::GenIntToLong(rl_dest, rl_src);
3211 return;
3212 }
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003213 rl_src = UpdateLocTyped(rl_src);
Chao-ying Fua0147762014-06-06 18:38:49 -07003214 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
3215 if (rl_src.location == kLocPhysReg) {
3216 NewLIR2(kX86MovsxdRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
3217 } else {
3218 int displacement = SRegOffset(rl_src.s_reg_low);
Vladimir Marko8dea81c2014-06-06 14:50:36 +01003219 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
Ian Rogersb28c1c02014-11-08 11:21:21 -08003220 LIR *m = NewLIR3(kX86MovsxdRM, rl_result.reg.GetReg(), rs_rX86_SP_32.GetReg(),
Chao-ying Fua0147762014-06-06 18:38:49 -07003221 displacement + LOWORD_OFFSET);
3222 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
3223 true /* is_load */, true /* is_64bit */);
3224 }
3225 StoreValueWide(rl_dest, rl_result);
3226}
3227
Yevgeny Rouban6af82062014-11-26 18:11:54 +06003228void X86Mir2Lir::GenLongToInt(RegLocation rl_dest, RegLocation rl_src) {
3229 rl_src = UpdateLocWide(rl_src);
3230 rl_src = NarrowRegLoc(rl_src);
3231 StoreValue(rl_dest, rl_src);
3232
3233 if (cu_->target64) {
3234 // if src and dest are in the same phys reg then StoreValue generates
3235 // no operation but we need explicit 32-bit mov R, R to clear
3236 // the higher 32-bits
3237 rl_dest = UpdateLoc(rl_dest);
3238 if (rl_src.location == kLocPhysReg && rl_dest.location == kLocPhysReg
3239 && IsSameReg(rl_src.reg, rl_dest.reg)) {
3240 LIR* copy_lir = OpRegCopyNoInsert(rl_dest.reg, rl_dest.reg);
3241 // remove nop flag set by OpRegCopyNoInsert if src == dest
3242 copy_lir->flags.is_nop = false;
3243 AppendLIR(copy_lir);
3244 }
3245 }
3246}
3247
Chao-ying Fua0147762014-06-06 18:38:49 -07003248void X86Mir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest,
3249 RegLocation rl_src1, RegLocation rl_shift) {
Elena Sayapinadd644502014-07-01 18:39:52 +07003250 if (!cu_->target64) {
Yixin Shouf40f8902014-08-14 14:10:32 -04003251 // Long shift operations in 32-bit. Use shld or shrd to create a 32-bit register filled from
3252 // the other half, shift the other half, if the shift amount is less than 32 we're done,
3253 // otherwise move one register to the other and place zero or sign bits in the other.
3254 LIR* branch;
3255 FlushAllRegs();
3256 LockCallTemps();
3257 LoadValueDirectFixed(rl_shift, rs_rCX);
3258 RegStorage r_tmp = RegStorage::MakeRegPair(rs_rAX, rs_rDX);
3259 LoadValueDirectWideFixed(rl_src1, r_tmp);
3260 switch (opcode) {
3261 case Instruction::SHL_LONG:
3262 case Instruction::SHL_LONG_2ADDR:
3263 NewLIR3(kX86Shld32RRC, r_tmp.GetHighReg(), r_tmp.GetLowReg(), rs_rCX.GetReg());
3264 NewLIR2(kX86Sal32RC, r_tmp.GetLowReg(), rs_rCX.GetReg());
3265 NewLIR2(kX86Test8RI, rs_rCX.GetReg(), 32);
3266 branch = NewLIR2(kX86Jcc8, 0, kX86CondZ);
3267 OpRegCopy(r_tmp.GetHigh(), r_tmp.GetLow());
3268 LoadConstant(r_tmp.GetLow(), 0);
3269 branch->target = NewLIR0(kPseudoTargetLabel);
3270 break;
3271 case Instruction::SHR_LONG:
3272 case Instruction::SHR_LONG_2ADDR:
3273 NewLIR3(kX86Shrd32RRC, r_tmp.GetLowReg(), r_tmp.GetHighReg(), rs_rCX.GetReg());
3274 NewLIR2(kX86Sar32RC, r_tmp.GetHighReg(), rs_rCX.GetReg());
3275 NewLIR2(kX86Test8RI, rs_rCX.GetReg(), 32);
3276 branch = NewLIR2(kX86Jcc8, 0, kX86CondZ);
3277 OpRegCopy(r_tmp.GetLow(), r_tmp.GetHigh());
3278 NewLIR2(kX86Sar32RI, r_tmp.GetHighReg(), 31);
3279 branch->target = NewLIR0(kPseudoTargetLabel);
3280 break;
3281 case Instruction::USHR_LONG:
3282 case Instruction::USHR_LONG_2ADDR:
3283 NewLIR3(kX86Shrd32RRC, r_tmp.GetLowReg(), r_tmp.GetHighReg(),
3284 rs_rCX.GetReg());
3285 NewLIR2(kX86Shr32RC, r_tmp.GetHighReg(), rs_rCX.GetReg());
3286 NewLIR2(kX86Test8RI, rs_rCX.GetReg(), 32);
3287 branch = NewLIR2(kX86Jcc8, 0, kX86CondZ);
3288 OpRegCopy(r_tmp.GetLow(), r_tmp.GetHigh());
3289 LoadConstant(r_tmp.GetHigh(), 0);
3290 branch->target = NewLIR0(kPseudoTargetLabel);
3291 break;
3292 default:
3293 LOG(FATAL) << "Unexpected case: " << opcode;
3294 return;
3295 }
3296 RegLocation rl_result = LocCReturnWide();
3297 StoreValueWide(rl_dest, rl_result);
Chao-ying Fua0147762014-06-06 18:38:49 -07003298 return;
3299 }
3300
3301 bool is_two_addr = false;
3302 OpKind op = kOpBkpt;
3303 RegLocation rl_result;
3304
3305 switch (opcode) {
3306 case Instruction::SHL_LONG_2ADDR:
3307 is_two_addr = true;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003308 FALLTHROUGH_INTENDED;
Chao-ying Fua0147762014-06-06 18:38:49 -07003309 case Instruction::SHL_LONG:
3310 op = kOpLsl;
3311 break;
3312 case Instruction::SHR_LONG_2ADDR:
3313 is_two_addr = true;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003314 FALLTHROUGH_INTENDED;
Chao-ying Fua0147762014-06-06 18:38:49 -07003315 case Instruction::SHR_LONG:
3316 op = kOpAsr;
3317 break;
3318 case Instruction::USHR_LONG_2ADDR:
3319 is_two_addr = true;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003320 FALLTHROUGH_INTENDED;
Chao-ying Fua0147762014-06-06 18:38:49 -07003321 case Instruction::USHR_LONG:
3322 op = kOpLsr;
3323 break;
3324 default:
3325 op = kOpBkpt;
3326 }
3327
3328 // X86 doesn't require masking and must use ECX.
Andreas Gampeccc60262014-07-04 18:02:38 -07003329 RegStorage t_reg = TargetReg(kCount, kNotWide); // rCX
Chao-ying Fua0147762014-06-06 18:38:49 -07003330 LoadValueDirectFixed(rl_shift, t_reg);
3331 if (is_two_addr) {
3332 // Can we do this directly into memory?
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003333 rl_result = UpdateLocWideTyped(rl_dest);
Chao-ying Fua0147762014-06-06 18:38:49 -07003334 if (rl_result.location != kLocPhysReg) {
3335 // Okay, we can do this into memory
Vladimir Marko8dea81c2014-06-06 14:50:36 +01003336 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
Chao-ying Fua0147762014-06-06 18:38:49 -07003337 OpMemReg(op, rl_result, t_reg.GetReg());
3338 } else if (!rl_result.reg.IsFloat()) {
3339 // Can do this directly into the result register
3340 OpRegReg(op, rl_result.reg, t_reg);
3341 StoreFinalValueWide(rl_dest, rl_result);
3342 }
3343 } else {
3344 // Three address form, or we can't do directly.
3345 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
3346 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
3347 OpRegRegReg(op, rl_result.reg, rl_src1.reg, t_reg);
3348 StoreFinalValueWide(rl_dest, rl_result);
3349 }
3350
3351 FreeTemp(t_reg);
3352}
3353
Brian Carlstrom7940e442013-07-12 13:46:57 -07003354} // namespace art