blob: 5ba9709187e3f715bef14e0c60db6dc6d68c7f6b [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* This file contains codegen for the X86 ISA */
18
19#include "codegen_x86.h"
20#include "dex/quick/mir_to_lir-inl.h"
21#include "mirror/array.h"
22#include "x86_lir.h"
23
24namespace art {
25
26/*
Brian Carlstrom7940e442013-07-12 13:46:57 -070027 * Compare two 64-bit values
28 * x = y return 0
29 * x < y return -1
30 * x > y return 1
31 */
32void X86Mir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070033 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070034 FlushAllRegs();
35 LockCallTemps(); // Prepare for explicit register usage
buzbee2700f7e2014-03-07 09:46:20 -080036 RegStorage r_tmp1(RegStorage::k64BitPair, r0, r1);
37 RegStorage r_tmp2(RegStorage::k64BitPair, r2, r3);
38 LoadValueDirectWideFixed(rl_src1, r_tmp1);
39 LoadValueDirectWideFixed(rl_src2, r_tmp2);
Brian Carlstrom7940e442013-07-12 13:46:57 -070040 // Compute (r1:r0) = (r1:r0) - (r3:r2)
buzbee2700f7e2014-03-07 09:46:20 -080041 OpRegReg(kOpSub, rs_r0, rs_r2); // r0 = r0 - r2
42 OpRegReg(kOpSbc, rs_r1, rs_r3); // r1 = r1 - r3 - CF
Brian Carlstrom7940e442013-07-12 13:46:57 -070043 NewLIR2(kX86Set8R, r2, kX86CondL); // r2 = (r1:r0) < (r3:r2) ? 1 : 0
44 NewLIR2(kX86Movzx8RR, r2, r2);
buzbee2700f7e2014-03-07 09:46:20 -080045 OpReg(kOpNeg, rs_r2); // r2 = -r2
46 OpRegReg(kOpOr, rs_r0, rs_r1); // r0 = high | low - sets ZF
Brian Carlstrom7940e442013-07-12 13:46:57 -070047 NewLIR2(kX86Set8R, r0, kX86CondNz); // r0 = (r1:r0) != (r3:r2) ? 1 : 0
48 NewLIR2(kX86Movzx8RR, r0, r0);
buzbee2700f7e2014-03-07 09:46:20 -080049 OpRegReg(kOpOr, rs_r0, rs_r2); // r0 = r0 | r2
Brian Carlstrom7940e442013-07-12 13:46:57 -070050 RegLocation rl_result = LocCReturn();
51 StoreValue(rl_dest, rl_result);
52}
53
54X86ConditionCode X86ConditionEncoding(ConditionCode cond) {
55 switch (cond) {
56 case kCondEq: return kX86CondEq;
57 case kCondNe: return kX86CondNe;
58 case kCondCs: return kX86CondC;
59 case kCondCc: return kX86CondNc;
Vladimir Marko58af1f92013-12-19 13:31:15 +000060 case kCondUlt: return kX86CondC;
61 case kCondUge: return kX86CondNc;
Brian Carlstrom7940e442013-07-12 13:46:57 -070062 case kCondMi: return kX86CondS;
63 case kCondPl: return kX86CondNs;
64 case kCondVs: return kX86CondO;
65 case kCondVc: return kX86CondNo;
66 case kCondHi: return kX86CondA;
67 case kCondLs: return kX86CondBe;
68 case kCondGe: return kX86CondGe;
69 case kCondLt: return kX86CondL;
70 case kCondGt: return kX86CondG;
71 case kCondLe: return kX86CondLe;
72 case kCondAl:
73 case kCondNv: LOG(FATAL) << "Should not reach here";
74 }
75 return kX86CondO;
76}
77
buzbee2700f7e2014-03-07 09:46:20 -080078LIR* X86Mir2Lir::OpCmpBranch(ConditionCode cond, RegStorage src1, RegStorage src2, LIR* target) {
79 NewLIR2(kX86Cmp32RR, src1.GetReg(), src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070080 X86ConditionCode cc = X86ConditionEncoding(cond);
81 LIR* branch = NewLIR2(kX86Jcc8, 0 /* lir operand for Jcc offset */ ,
82 cc);
83 branch->target = target;
84 return branch;
85}
86
buzbee2700f7e2014-03-07 09:46:20 -080087LIR* X86Mir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070088 int check_value, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070089 if ((check_value == 0) && (cond == kCondEq || cond == kCondNe)) {
90 // TODO: when check_value == 0 and reg is rCX, use the jcxz/nz opcode
buzbee2700f7e2014-03-07 09:46:20 -080091 NewLIR2(kX86Test32RR, reg.GetReg(), reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070092 } else {
buzbee2700f7e2014-03-07 09:46:20 -080093 NewLIR2(IS_SIMM8(check_value) ? kX86Cmp32RI8 : kX86Cmp32RI, reg.GetReg(), check_value);
Brian Carlstrom7940e442013-07-12 13:46:57 -070094 }
95 X86ConditionCode cc = X86ConditionEncoding(cond);
96 LIR* branch = NewLIR2(kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc);
97 branch->target = target;
98 return branch;
99}
100
buzbee2700f7e2014-03-07 09:46:20 -0800101LIR* X86Mir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) {
102 // If src or dest is a pair, we'll be using low reg.
103 if (r_dest.IsPair()) {
104 r_dest = r_dest.GetLow();
105 }
106 if (r_src.IsPair()) {
107 r_src = r_src.GetLow();
108 }
109 if (X86_FPREG(r_dest.GetReg()) || X86_FPREG(r_src.GetReg()))
Brian Carlstrom7940e442013-07-12 13:46:57 -0700110 return OpFpRegCopy(r_dest, r_src);
111 LIR* res = RawLIR(current_dalvik_offset_, kX86Mov32RR,
buzbee2700f7e2014-03-07 09:46:20 -0800112 r_dest.GetReg(), r_src.GetReg());
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800113 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700114 res->flags.is_nop = true;
115 }
116 return res;
117}
118
buzbee2700f7e2014-03-07 09:46:20 -0800119LIR* X86Mir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700120 LIR *res = OpRegCopyNoInsert(r_dest, r_src);
121 AppendLIR(res);
122 return res;
123}
124
buzbee2700f7e2014-03-07 09:46:20 -0800125void X86Mir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
126 // FIXME: handle k64BitSolo when we start using them.
127 DCHECK(r_dest.IsPair());
128 DCHECK(r_src.IsPair());
129 bool dest_fp = X86_FPREG(r_dest.GetLowReg());
130 bool src_fp = X86_FPREG(r_src.GetLowReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700131 if (dest_fp) {
132 if (src_fp) {
buzbee2700f7e2014-03-07 09:46:20 -0800133 // TODO: we ought to handle this case here - reserve OpRegCopy for 32-bit copies.
134 OpRegCopy(RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg())),
135 RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg())));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700136 } else {
137 // TODO: Prevent this from happening in the code. The result is often
138 // unused or could have been loaded more easily from memory.
buzbee2700f7e2014-03-07 09:46:20 -0800139 NewLIR2(kX86MovdxrRR, r_dest.GetLowReg(), r_src.GetLowReg());
140 RegStorage r_tmp = AllocTempDouble();
141 NewLIR2(kX86MovdxrRR, r_tmp.GetLowReg(), r_src.GetHighReg());
142 NewLIR2(kX86PunpckldqRR, r_dest.GetLowReg(), r_tmp.GetLowReg());
143 FreeTemp(r_tmp);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700144 }
145 } else {
146 if (src_fp) {
buzbee2700f7e2014-03-07 09:46:20 -0800147 NewLIR2(kX86MovdrxRR, r_dest.GetLowReg(), r_src.GetLowReg());
148 NewLIR2(kX86PsrlqRI, r_src.GetLowReg(), 32);
149 NewLIR2(kX86MovdrxRR, r_dest.GetHighReg(), r_src.GetLowReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700150 } else {
151 // Handle overlap
buzbee2700f7e2014-03-07 09:46:20 -0800152 if (r_src.GetHighReg() == r_dest.GetLowReg() && r_src.GetLowReg() == r_dest.GetHighReg()) {
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800153 // Deal with cycles.
buzbee2700f7e2014-03-07 09:46:20 -0800154 RegStorage temp_reg = AllocTemp();
155 OpRegCopy(temp_reg, r_dest.GetHigh());
156 OpRegCopy(r_dest.GetHigh(), r_dest.GetLow());
157 OpRegCopy(r_dest.GetLow(), temp_reg);
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800158 FreeTemp(temp_reg);
buzbee2700f7e2014-03-07 09:46:20 -0800159 } else if (r_src.GetHighReg() == r_dest.GetLowReg()) {
160 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
161 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700162 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800163 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
164 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700165 }
166 }
167 }
168}
169
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700170void X86Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800171 RegLocation rl_result;
172 RegLocation rl_src = mir_graph_->GetSrc(mir, 0);
173 RegLocation rl_dest = mir_graph_->GetDest(mir);
174 rl_src = LoadValue(rl_src, kCoreReg);
Vladimir Markoa1a70742014-03-03 10:28:05 +0000175 ConditionCode ccode = mir->meta.ccode;
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800176
177 // The kMirOpSelect has two variants, one for constants and one for moves.
178 const bool is_constant_case = (mir->ssa_rep->num_uses == 1);
179
180 if (is_constant_case) {
181 int true_val = mir->dalvikInsn.vB;
182 int false_val = mir->dalvikInsn.vC;
183 rl_result = EvalLoc(rl_dest, kCoreReg, true);
184
185 /*
Vladimir Markoa1a70742014-03-03 10:28:05 +0000186 * For ccode == kCondEq:
187 *
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800188 * 1) When the true case is zero and result_reg is not same as src_reg:
189 * xor result_reg, result_reg
190 * cmp $0, src_reg
191 * mov t1, $false_case
192 * cmovnz result_reg, t1
193 * 2) When the false case is zero and result_reg is not same as src_reg:
194 * xor result_reg, result_reg
195 * cmp $0, src_reg
196 * mov t1, $true_case
197 * cmovz result_reg, t1
198 * 3) All other cases (we do compare first to set eflags):
199 * cmp $0, src_reg
Vladimir Markoa1a70742014-03-03 10:28:05 +0000200 * mov result_reg, $false_case
201 * mov t1, $true_case
202 * cmovz result_reg, t1
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800203 */
buzbee2700f7e2014-03-07 09:46:20 -0800204 const bool result_reg_same_as_src =
205 (rl_src.location == kLocPhysReg && rl_src.reg.GetReg() == rl_result.reg.GetReg());
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800206 const bool true_zero_case = (true_val == 0 && false_val != 0 && !result_reg_same_as_src);
207 const bool false_zero_case = (false_val == 0 && true_val != 0 && !result_reg_same_as_src);
208 const bool catch_all_case = !(true_zero_case || false_zero_case);
209
210 if (true_zero_case || false_zero_case) {
buzbee2700f7e2014-03-07 09:46:20 -0800211 OpRegReg(kOpXor, rl_result.reg, rl_result.reg);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800212 }
213
214 if (true_zero_case || false_zero_case || catch_all_case) {
buzbee2700f7e2014-03-07 09:46:20 -0800215 OpRegImm(kOpCmp, rl_src.reg, 0);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800216 }
217
218 if (catch_all_case) {
buzbee2700f7e2014-03-07 09:46:20 -0800219 OpRegImm(kOpMov, rl_result.reg, false_val);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800220 }
221
222 if (true_zero_case || false_zero_case || catch_all_case) {
Vladimir Markoa1a70742014-03-03 10:28:05 +0000223 ConditionCode cc = true_zero_case ? NegateComparison(ccode) : ccode;
224 int immediateForTemp = true_zero_case ? false_val : true_val;
buzbee2700f7e2014-03-07 09:46:20 -0800225 RegStorage temp1_reg = AllocTemp();
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800226 OpRegImm(kOpMov, temp1_reg, immediateForTemp);
227
buzbee2700f7e2014-03-07 09:46:20 -0800228 OpCondRegReg(kOpCmov, cc, rl_result.reg, temp1_reg);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800229
230 FreeTemp(temp1_reg);
231 }
232 } else {
233 RegLocation rl_true = mir_graph_->GetSrc(mir, 1);
234 RegLocation rl_false = mir_graph_->GetSrc(mir, 2);
235 rl_true = LoadValue(rl_true, kCoreReg);
236 rl_false = LoadValue(rl_false, kCoreReg);
237 rl_result = EvalLoc(rl_dest, kCoreReg, true);
238
239 /*
Vladimir Markoa1a70742014-03-03 10:28:05 +0000240 * For ccode == kCondEq:
241 *
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800242 * 1) When true case is already in place:
243 * cmp $0, src_reg
244 * cmovnz result_reg, false_reg
245 * 2) When false case is already in place:
246 * cmp $0, src_reg
247 * cmovz result_reg, true_reg
248 * 3) When neither cases are in place:
249 * cmp $0, src_reg
Vladimir Markoa1a70742014-03-03 10:28:05 +0000250 * mov result_reg, false_reg
251 * cmovz result_reg, true_reg
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800252 */
253
254 // kMirOpSelect is generated just for conditional cases when comparison is done with zero.
buzbee2700f7e2014-03-07 09:46:20 -0800255 OpRegImm(kOpCmp, rl_src.reg, 0);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800256
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000257 if (rl_result.reg.GetReg() == rl_true.reg.GetReg()) {
buzbee2700f7e2014-03-07 09:46:20 -0800258 OpCondRegReg(kOpCmov, NegateComparison(ccode), rl_result.reg, rl_false.reg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000259 } else if (rl_result.reg.GetReg() == rl_false.reg.GetReg()) {
buzbee2700f7e2014-03-07 09:46:20 -0800260 OpCondRegReg(kOpCmov, ccode, rl_result.reg, rl_true.reg);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800261 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800262 OpRegCopy(rl_result.reg, rl_false.reg);
263 OpCondRegReg(kOpCmov, ccode, rl_result.reg, rl_true.reg);
Razvan A Lupusorue27b3bf2014-01-23 09:41:45 -0800264 }
265 }
266
267 StoreValue(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700268}
269
270void X86Mir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
buzbee0d829482013-10-11 15:24:55 -0700271 LIR* taken = &block_label_list_[bb->taken];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700272 RegLocation rl_src1 = mir_graph_->GetSrcWide(mir, 0);
273 RegLocation rl_src2 = mir_graph_->GetSrcWide(mir, 2);
Vladimir Markoa8946072014-01-22 10:30:44 +0000274 ConditionCode ccode = mir->meta.ccode;
Mark Mendell412d4f82013-12-18 13:32:36 -0800275
276 if (rl_src1.is_const) {
277 std::swap(rl_src1, rl_src2);
278 ccode = FlipComparisonOrder(ccode);
279 }
280 if (rl_src2.is_const) {
281 // Do special compare/branch against simple const operand
282 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
283 GenFusedLongCmpImmBranch(bb, rl_src1, val, ccode);
284 return;
285 }
286
Brian Carlstrom7940e442013-07-12 13:46:57 -0700287 FlushAllRegs();
288 LockCallTemps(); // Prepare for explicit register usage
buzbee2700f7e2014-03-07 09:46:20 -0800289 RegStorage r_tmp1(RegStorage::k64BitPair, r0, r1);
290 RegStorage r_tmp2(RegStorage::k64BitPair, r2, r3);
291 LoadValueDirectWideFixed(rl_src1, r_tmp1);
292 LoadValueDirectWideFixed(rl_src2, r_tmp2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700293 // Swap operands and condition code to prevent use of zero flag.
294 if (ccode == kCondLe || ccode == kCondGt) {
295 // Compute (r3:r2) = (r3:r2) - (r1:r0)
buzbee2700f7e2014-03-07 09:46:20 -0800296 OpRegReg(kOpSub, rs_r2, rs_r0); // r2 = r2 - r0
297 OpRegReg(kOpSbc, rs_r3, rs_r1); // r3 = r3 - r1 - CF
Brian Carlstrom7940e442013-07-12 13:46:57 -0700298 } else {
299 // Compute (r1:r0) = (r1:r0) - (r3:r2)
buzbee2700f7e2014-03-07 09:46:20 -0800300 OpRegReg(kOpSub, rs_r0, rs_r2); // r0 = r0 - r2
301 OpRegReg(kOpSbc, rs_r1, rs_r3); // r1 = r1 - r3 - CF
Brian Carlstrom7940e442013-07-12 13:46:57 -0700302 }
303 switch (ccode) {
304 case kCondEq:
305 case kCondNe:
buzbee2700f7e2014-03-07 09:46:20 -0800306 OpRegReg(kOpOr, rs_r0, rs_r1); // r0 = r0 | r1
Brian Carlstrom7940e442013-07-12 13:46:57 -0700307 break;
308 case kCondLe:
309 ccode = kCondGe;
310 break;
311 case kCondGt:
312 ccode = kCondLt;
313 break;
314 case kCondLt:
315 case kCondGe:
316 break;
317 default:
318 LOG(FATAL) << "Unexpected ccode: " << ccode;
319 }
320 OpCondBranch(ccode, taken);
321}
322
Mark Mendell412d4f82013-12-18 13:32:36 -0800323void X86Mir2Lir::GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1,
324 int64_t val, ConditionCode ccode) {
325 int32_t val_lo = Low32Bits(val);
326 int32_t val_hi = High32Bits(val);
327 LIR* taken = &block_label_list_[bb->taken];
328 LIR* not_taken = &block_label_list_[bb->fall_through];
329 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
buzbee2700f7e2014-03-07 09:46:20 -0800330 RegStorage low_reg = rl_src1.reg.GetLow();
331 RegStorage high_reg = rl_src1.reg.GetHigh();
Mark Mendell412d4f82013-12-18 13:32:36 -0800332
333 if (val == 0 && (ccode == kCondEq || ccode == kCondNe)) {
buzbee2700f7e2014-03-07 09:46:20 -0800334 RegStorage t_reg = AllocTemp();
Mark Mendell412d4f82013-12-18 13:32:36 -0800335 OpRegRegReg(kOpOr, t_reg, low_reg, high_reg);
336 FreeTemp(t_reg);
337 OpCondBranch(ccode, taken);
338 return;
339 }
340
341 OpRegImm(kOpCmp, high_reg, val_hi);
342 switch (ccode) {
343 case kCondEq:
344 case kCondNe:
345 OpCondBranch(kCondNe, (ccode == kCondEq) ? not_taken : taken);
346 break;
347 case kCondLt:
348 OpCondBranch(kCondLt, taken);
349 OpCondBranch(kCondGt, not_taken);
350 ccode = kCondUlt;
351 break;
352 case kCondLe:
353 OpCondBranch(kCondLt, taken);
354 OpCondBranch(kCondGt, not_taken);
355 ccode = kCondLs;
356 break;
357 case kCondGt:
358 OpCondBranch(kCondGt, taken);
359 OpCondBranch(kCondLt, not_taken);
360 ccode = kCondHi;
361 break;
362 case kCondGe:
363 OpCondBranch(kCondGt, taken);
364 OpCondBranch(kCondLt, not_taken);
365 ccode = kCondUge;
366 break;
367 default:
368 LOG(FATAL) << "Unexpected ccode: " << ccode;
369 }
370 OpCmpImmBranch(ccode, low_reg, val_lo, taken);
371}
372
Mark Mendell2bf31e62014-01-23 12:13:40 -0800373void X86Mir2Lir::CalculateMagicAndShift(int divisor, int& magic, int& shift) {
374 // It does not make sense to calculate magic and shift for zero divisor.
375 DCHECK_NE(divisor, 0);
376
377 /* According to H.S.Warren's Hacker's Delight Chapter 10 and
378 * T,Grablund, P.L.Montogomery's Division by invariant integers using multiplication.
379 * The magic number M and shift S can be calculated in the following way:
380 * Let nc be the most positive value of numerator(n) such that nc = kd - 1,
381 * where divisor(d) >=2.
382 * Let nc be the most negative value of numerator(n) such that nc = kd + 1,
383 * where divisor(d) <= -2.
384 * Thus nc can be calculated like:
385 * nc = 2^31 + 2^31 % d - 1, where d >= 2
386 * nc = -2^31 + (2^31 + 1) % d, where d >= 2.
387 *
388 * So the shift p is the smallest p satisfying
389 * 2^p > nc * (d - 2^p % d), where d >= 2
390 * 2^p > nc * (d + 2^p % d), where d <= -2.
391 *
392 * the magic number M is calcuated by
393 * M = (2^p + d - 2^p % d) / d, where d >= 2
394 * M = (2^p - d - 2^p % d) / d, where d <= -2.
395 *
396 * Notice that p is always bigger than or equal to 32, so we just return 32-p as
397 * the shift number S.
398 */
399
400 int32_t p = 31;
401 const uint32_t two31 = 0x80000000U;
402
403 // Initialize the computations.
404 uint32_t abs_d = (divisor >= 0) ? divisor : -divisor;
405 uint32_t tmp = two31 + (static_cast<uint32_t>(divisor) >> 31);
406 uint32_t abs_nc = tmp - 1 - tmp % abs_d;
407 uint32_t quotient1 = two31 / abs_nc;
408 uint32_t remainder1 = two31 % abs_nc;
409 uint32_t quotient2 = two31 / abs_d;
410 uint32_t remainder2 = two31 % abs_d;
411
412 /*
413 * To avoid handling both positive and negative divisor, Hacker's Delight
414 * introduces a method to handle these 2 cases together to avoid duplication.
415 */
416 uint32_t delta;
417 do {
418 p++;
419 quotient1 = 2 * quotient1;
420 remainder1 = 2 * remainder1;
421 if (remainder1 >= abs_nc) {
422 quotient1++;
423 remainder1 = remainder1 - abs_nc;
424 }
425 quotient2 = 2 * quotient2;
426 remainder2 = 2 * remainder2;
427 if (remainder2 >= abs_d) {
428 quotient2++;
429 remainder2 = remainder2 - abs_d;
430 }
431 delta = abs_d - remainder2;
432 } while (quotient1 < delta || (quotient1 == delta && remainder1 == 0));
433
434 magic = (divisor > 0) ? (quotient2 + 1) : (-quotient2 - 1);
435 shift = p - 32;
436}
437
buzbee2700f7e2014-03-07 09:46:20 -0800438RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg_lo, int lit, bool is_div) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700439 LOG(FATAL) << "Unexpected use of GenDivRemLit for x86";
440 return rl_dest;
441}
442
Mark Mendell2bf31e62014-01-23 12:13:40 -0800443RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src,
444 int imm, bool is_div) {
445 // Use a multiply (and fixup) to perform an int div/rem by a constant.
446
447 // We have to use fixed registers, so flush all the temps.
448 FlushAllRegs();
449 LockCallTemps(); // Prepare for explicit register usage.
450
451 // Assume that the result will be in EDX.
buzbee2700f7e2014-03-07 09:46:20 -0800452 RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, rs_r2,
453 INVALID_SREG, INVALID_SREG};
Mark Mendell2bf31e62014-01-23 12:13:40 -0800454
Alexei Zavjalov79aa4232014-02-13 13:55:50 +0700455 // handle div/rem by 1 special case.
456 if (imm == 1) {
Mark Mendell2bf31e62014-01-23 12:13:40 -0800457 if (is_div) {
Alexei Zavjalov79aa4232014-02-13 13:55:50 +0700458 // x / 1 == x.
459 StoreValue(rl_result, rl_src);
460 } else {
461 // x % 1 == 0.
buzbee2700f7e2014-03-07 09:46:20 -0800462 LoadConstantNoClobber(rs_r0, 0);
Alexei Zavjalov79aa4232014-02-13 13:55:50 +0700463 // For this case, return the result in EAX.
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000464 rl_result.reg.SetReg(r0);
Alexei Zavjalov79aa4232014-02-13 13:55:50 +0700465 }
466 } else if (imm == -1) { // handle 0x80000000 / -1 special case.
467 if (is_div) {
468 LIR *minint_branch = 0;
buzbee2700f7e2014-03-07 09:46:20 -0800469 LoadValueDirectFixed(rl_src, rs_r0);
470 OpRegImm(kOpCmp, rs_r0, 0x80000000);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800471 minint_branch = NewLIR2(kX86Jcc8, 0, kX86CondEq);
472
473 // for x != MIN_INT, x / -1 == -x.
474 NewLIR1(kX86Neg32R, r0);
475
476 LIR* branch_around = NewLIR1(kX86Jmp8, 0);
477 // The target for cmp/jmp above.
478 minint_branch->target = NewLIR0(kPseudoTargetLabel);
479 // EAX already contains the right value (0x80000000),
480 branch_around->target = NewLIR0(kPseudoTargetLabel);
481 } else {
482 // x % -1 == 0.
buzbee2700f7e2014-03-07 09:46:20 -0800483 LoadConstantNoClobber(rs_r0, 0);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800484 }
485 // For this case, return the result in EAX.
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000486 rl_result.reg.SetReg(r0);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800487 } else {
Alexei Zavjalov79aa4232014-02-13 13:55:50 +0700488 CHECK(imm <= -2 || imm >= 2);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800489 // Use H.S.Warren's Hacker's Delight Chapter 10 and
490 // T,Grablund, P.L.Montogomery's Division by invariant integers using multiplication.
491 int magic, shift;
492 CalculateMagicAndShift(imm, magic, shift);
493
494 /*
495 * For imm >= 2,
496 * int(n/imm) = floor(n/imm) = floor(M*n/2^S), while n > 0
497 * int(n/imm) = ceil(n/imm) = floor(M*n/2^S) +1, while n < 0.
498 * For imm <= -2,
499 * int(n/imm) = ceil(n/imm) = floor(M*n/2^S) +1 , while n > 0
500 * int(n/imm) = floor(n/imm) = floor(M*n/2^S), while n < 0.
501 * We implement this algorithm in the following way:
502 * 1. multiply magic number m and numerator n, get the higher 32bit result in EDX
503 * 2. if imm > 0 and magic < 0, add numerator to EDX
504 * if imm < 0 and magic > 0, sub numerator from EDX
505 * 3. if S !=0, SAR S bits for EDX
506 * 4. add 1 to EDX if EDX < 0
507 * 5. Thus, EDX is the quotient
508 */
509
510 // Numerator into EAX.
buzbee2700f7e2014-03-07 09:46:20 -0800511 RegStorage numerator_reg;
Mark Mendell2bf31e62014-01-23 12:13:40 -0800512 if (!is_div || (imm > 0 && magic < 0) || (imm < 0 && magic > 0)) {
513 // We will need the value later.
514 if (rl_src.location == kLocPhysReg) {
515 // We can use it directly.
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000516 DCHECK(rl_src.reg.GetReg() != r0 && rl_src.reg.GetReg() != r2);
buzbee2700f7e2014-03-07 09:46:20 -0800517 numerator_reg = rl_src.reg;
Mark Mendell2bf31e62014-01-23 12:13:40 -0800518 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800519 numerator_reg = rs_r1;
520 LoadValueDirectFixed(rl_src, numerator_reg);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800521 }
buzbee2700f7e2014-03-07 09:46:20 -0800522 OpRegCopy(rs_r0, numerator_reg);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800523 } else {
524 // Only need this once. Just put it into EAX.
buzbee2700f7e2014-03-07 09:46:20 -0800525 LoadValueDirectFixed(rl_src, rs_r0);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800526 }
527
528 // EDX = magic.
buzbee2700f7e2014-03-07 09:46:20 -0800529 LoadConstantNoClobber(rs_r2, magic);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800530
531 // EDX:EAX = magic & dividend.
532 NewLIR1(kX86Imul32DaR, r2);
533
534 if (imm > 0 && magic < 0) {
535 // Add numerator to EDX.
buzbee2700f7e2014-03-07 09:46:20 -0800536 DCHECK(numerator_reg.Valid());
537 NewLIR2(kX86Add32RR, r2, numerator_reg.GetReg());
Mark Mendell2bf31e62014-01-23 12:13:40 -0800538 } else if (imm < 0 && magic > 0) {
buzbee2700f7e2014-03-07 09:46:20 -0800539 DCHECK(numerator_reg.Valid());
540 NewLIR2(kX86Sub32RR, r2, numerator_reg.GetReg());
Mark Mendell2bf31e62014-01-23 12:13:40 -0800541 }
542
543 // Do we need the shift?
544 if (shift != 0) {
545 // Shift EDX by 'shift' bits.
546 NewLIR2(kX86Sar32RI, r2, shift);
547 }
548
549 // Add 1 to EDX if EDX < 0.
550
551 // Move EDX to EAX.
buzbee2700f7e2014-03-07 09:46:20 -0800552 OpRegCopy(rs_r0, rs_r2);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800553
554 // Move sign bit to bit 0, zeroing the rest.
555 NewLIR2(kX86Shr32RI, r2, 31);
556
557 // EDX = EDX + EAX.
558 NewLIR2(kX86Add32RR, r2, r0);
559
560 // Quotient is in EDX.
561 if (!is_div) {
562 // We need to compute the remainder.
563 // Remainder is divisor - (quotient * imm).
buzbee2700f7e2014-03-07 09:46:20 -0800564 DCHECK(numerator_reg.Valid());
565 OpRegCopy(rs_r0, numerator_reg);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800566
567 // EAX = numerator * imm.
buzbee2700f7e2014-03-07 09:46:20 -0800568 OpRegRegImm(kOpMul, rs_r2, rs_r2, imm);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800569
570 // EDX -= EAX.
571 NewLIR2(kX86Sub32RR, r0, r2);
572
573 // For this case, return the result in EAX.
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000574 rl_result.reg.SetReg(r0);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800575 }
576 }
577
578 return rl_result;
579}
580
buzbee2700f7e2014-03-07 09:46:20 -0800581RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg_lo, RegStorage reg_hi,
582 bool is_div) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700583 LOG(FATAL) << "Unexpected use of GenDivRem for x86";
584 return rl_dest;
585}
586
Mark Mendell2bf31e62014-01-23 12:13:40 -0800587RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
588 RegLocation rl_src2, bool is_div, bool check_zero) {
589 // We have to use fixed registers, so flush all the temps.
590 FlushAllRegs();
591 LockCallTemps(); // Prepare for explicit register usage.
592
593 // Load LHS into EAX.
buzbee2700f7e2014-03-07 09:46:20 -0800594 LoadValueDirectFixed(rl_src1, rs_r0);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800595
596 // Load RHS into EBX.
buzbee2700f7e2014-03-07 09:46:20 -0800597 LoadValueDirectFixed(rl_src2, rs_r1);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800598
599 // Copy LHS sign bit into EDX.
600 NewLIR0(kx86Cdq32Da);
601
602 if (check_zero) {
603 // Handle division by zero case.
Mingyao Yange643a172014-04-08 11:02:52 -0700604 GenDivZeroCheck(rs_r1);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800605 }
606
607 // Have to catch 0x80000000/-1 case, or we will get an exception!
buzbee2700f7e2014-03-07 09:46:20 -0800608 OpRegImm(kOpCmp, rs_r1, -1);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800609 LIR *minus_one_branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
610
611 // RHS is -1.
buzbee2700f7e2014-03-07 09:46:20 -0800612 OpRegImm(kOpCmp, rs_r0, 0x80000000);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800613 LIR * minint_branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
614
615 // In 0x80000000/-1 case.
616 if (!is_div) {
617 // For DIV, EAX is already right. For REM, we need EDX 0.
buzbee2700f7e2014-03-07 09:46:20 -0800618 LoadConstantNoClobber(rs_r2, 0);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800619 }
620 LIR* done = NewLIR1(kX86Jmp8, 0);
621
622 // Expected case.
623 minus_one_branch->target = NewLIR0(kPseudoTargetLabel);
624 minint_branch->target = minus_one_branch->target;
625 NewLIR1(kX86Idivmod32DaR, r1);
626 done->target = NewLIR0(kPseudoTargetLabel);
627
628 // Result is in EAX for div and EDX for rem.
buzbee2700f7e2014-03-07 09:46:20 -0800629 RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, rs_r0,
630 INVALID_SREG, INVALID_SREG};
Mark Mendell2bf31e62014-01-23 12:13:40 -0800631 if (!is_div) {
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000632 rl_result.reg.SetReg(r2);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800633 }
634 return rl_result;
635}
636
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700637bool X86Mir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) {
Dmitry Petrochenko6a58cb12014-04-02 17:27:59 +0700638 DCHECK(cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800639
640 // Get the two arguments to the invoke and place them in GP registers.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700641 RegLocation rl_src1 = info->args[0];
642 RegLocation rl_src2 = info->args[1];
643 rl_src1 = LoadValue(rl_src1, kCoreReg);
644 rl_src2 = LoadValue(rl_src2, kCoreReg);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800645
Brian Carlstrom7940e442013-07-12 13:46:57 -0700646 RegLocation rl_dest = InlineTarget(info);
647 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800648
649 /*
650 * If the result register is the same as the second element, then we need to be careful.
651 * The reason is that the first copy will inadvertently clobber the second element with
652 * the first one thus yielding the wrong result. Thus we do a swap in that case.
653 */
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000654 if (rl_result.reg.GetReg() == rl_src2.reg.GetReg()) {
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800655 std::swap(rl_src1, rl_src2);
656 }
657
658 // Pick the first integer as min/max.
buzbee2700f7e2014-03-07 09:46:20 -0800659 OpRegCopy(rl_result.reg, rl_src1.reg);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800660
661 // If the integers are both in the same register, then there is nothing else to do
662 // because they are equal and we have already moved one into the result.
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000663 if (rl_src1.reg.GetReg() != rl_src2.reg.GetReg()) {
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800664 // It is possible we didn't pick correctly so do the actual comparison now.
buzbee2700f7e2014-03-07 09:46:20 -0800665 OpRegReg(kOpCmp, rl_src1.reg, rl_src2.reg);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800666
667 // Conditionally move the other integer into the destination register.
668 ConditionCode condition_code = is_min ? kCondGt : kCondLt;
buzbee2700f7e2014-03-07 09:46:20 -0800669 OpCondRegReg(kOpCmov, condition_code, rl_result.reg, rl_src2.reg);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800670 }
671
Brian Carlstrom7940e442013-07-12 13:46:57 -0700672 StoreValue(rl_dest, rl_result);
673 return true;
674}
675
Vladimir Markoe508a202013-11-04 15:24:22 +0000676bool X86Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
677 RegLocation rl_src_address = info->args[0]; // long address
buzbee2700f7e2014-03-07 09:46:20 -0800678 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1]
buzbee695d13a2014-04-19 13:32:20 -0700679 RegLocation rl_dest = size == k64 ? InlineTargetWide(info) : InlineTarget(info);
Vladimir Markoe508a202013-11-04 15:24:22 +0000680 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
681 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee695d13a2014-04-19 13:32:20 -0700682 if (size == k64) {
Vladimir Markoe508a202013-11-04 15:24:22 +0000683 // Unaligned access is allowed on x86.
buzbee2700f7e2014-03-07 09:46:20 -0800684 LoadBaseDispWide(rl_address.reg, 0, rl_result.reg, INVALID_SREG);
Vladimir Markoe508a202013-11-04 15:24:22 +0000685 StoreValueWide(rl_dest, rl_result);
686 } else {
buzbee695d13a2014-04-19 13:32:20 -0700687 DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
Vladimir Markoe508a202013-11-04 15:24:22 +0000688 // Unaligned access is allowed on x86.
buzbee2700f7e2014-03-07 09:46:20 -0800689 LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, INVALID_SREG);
Vladimir Markoe508a202013-11-04 15:24:22 +0000690 StoreValue(rl_dest, rl_result);
691 }
692 return true;
693}
694
695bool X86Mir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
696 RegLocation rl_src_address = info->args[0]; // long address
buzbee2700f7e2014-03-07 09:46:20 -0800697 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1]
Vladimir Markoe508a202013-11-04 15:24:22 +0000698 RegLocation rl_src_value = info->args[2]; // [size] value
699 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
buzbee695d13a2014-04-19 13:32:20 -0700700 if (size == k64) {
Vladimir Markoe508a202013-11-04 15:24:22 +0000701 // Unaligned access is allowed on x86.
702 RegLocation rl_value = LoadValueWide(rl_src_value, kCoreReg);
buzbee2700f7e2014-03-07 09:46:20 -0800703 StoreBaseDispWide(rl_address.reg, 0, rl_value.reg);
Vladimir Markoe508a202013-11-04 15:24:22 +0000704 } else {
buzbee695d13a2014-04-19 13:32:20 -0700705 DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
Vladimir Markoe508a202013-11-04 15:24:22 +0000706 // Unaligned access is allowed on x86.
707 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
buzbee2700f7e2014-03-07 09:46:20 -0800708 StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size);
Vladimir Markoe508a202013-11-04 15:24:22 +0000709 }
710 return true;
711}
712
buzbee2700f7e2014-03-07 09:46:20 -0800713void X86Mir2Lir::OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale, int offset) {
714 NewLIR5(kX86Lea32RA, r_base.GetReg(), reg1.GetReg(), reg2.GetReg(), scale, offset);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700715}
716
Ian Rogersdd7624d2014-03-14 17:43:00 -0700717void X86Mir2Lir::OpTlsCmp(ThreadOffset<4> offset, int val) {
Ian Rogers468532e2013-08-05 10:56:33 -0700718 NewLIR2(kX86Cmp16TI8, offset.Int32Value(), val);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700719}
720
buzbee2700f7e2014-03-07 09:46:20 -0800721static bool IsInReg(X86Mir2Lir *pMir2Lir, const RegLocation &rl, RegStorage reg) {
722 return rl.reg.Valid() && rl.reg.GetReg() == reg.GetReg() && (pMir2Lir->IsLive(reg) || rl.home);
Yevgeny Rouband3a2dfa2014-03-18 15:55:16 +0700723}
724
Vladimir Marko1c282e22013-11-21 14:49:47 +0000725bool X86Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
Dmitry Petrochenko6a58cb12014-04-02 17:27:59 +0700726 DCHECK(cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64);
Vladimir Markoc29bb612013-11-27 16:47:25 +0000727 // Unused - RegLocation rl_src_unsafe = info->args[0];
728 RegLocation rl_src_obj = info->args[1]; // Object - known non-null
729 RegLocation rl_src_offset = info->args[2]; // long low
buzbee2700f7e2014-03-07 09:46:20 -0800730 rl_src_offset = NarrowRegLoc(rl_src_offset); // ignore high half in info->args[3]
Vladimir Markoc29bb612013-11-27 16:47:25 +0000731 RegLocation rl_src_expected = info->args[4]; // int, long or Object
732 // If is_long, high half is in info->args[5]
733 RegLocation rl_src_new_value = info->args[is_long ? 6 : 5]; // int, long or Object
734 // If is_long, high half is in info->args[7]
735
736 if (is_long) {
Yevgeny Rouband3a2dfa2014-03-18 15:55:16 +0700737 // TODO: avoid unnecessary loads of SI and DI when the values are in registers.
738 // TODO: CFI support.
Vladimir Marko70b797d2013-12-03 15:25:24 +0000739 FlushAllRegs();
740 LockCallTemps();
buzbee2700f7e2014-03-07 09:46:20 -0800741 RegStorage r_tmp1(RegStorage::k64BitPair, rAX, rDX);
742 RegStorage r_tmp2(RegStorage::k64BitPair, rBX, rCX);
743 LoadValueDirectWideFixed(rl_src_expected, r_tmp1);
744 LoadValueDirectWideFixed(rl_src_new_value, r_tmp2);
Vladimir Marko70b797d2013-12-03 15:25:24 +0000745 NewLIR1(kX86Push32R, rDI);
746 MarkTemp(rDI);
747 LockTemp(rDI);
748 NewLIR1(kX86Push32R, rSI);
749 MarkTemp(rSI);
750 LockTemp(rSI);
Vladimir Markoa6fd8ba2013-12-13 10:53:49 +0000751 const int push_offset = 4 /* push edi */ + 4 /* push esi */;
buzbee2700f7e2014-03-07 09:46:20 -0800752 int srcObjSp = IsInReg(this, rl_src_obj, rs_rSI) ? 0
753 : (IsInReg(this, rl_src_obj, rs_rDI) ? 4
Yevgeny Rouband3a2dfa2014-03-18 15:55:16 +0700754 : (SRegOffset(rl_src_obj.s_reg_low) + push_offset));
buzbee695d13a2014-04-19 13:32:20 -0700755 // FIXME: needs 64-bit update.
buzbee2700f7e2014-03-07 09:46:20 -0800756 LoadWordDisp(TargetReg(kSp), srcObjSp, rs_rDI);
757 int srcOffsetSp = IsInReg(this, rl_src_offset, rs_rSI) ? 0
758 : (IsInReg(this, rl_src_offset, rs_rDI) ? 4
Yevgeny Rouband3a2dfa2014-03-18 15:55:16 +0700759 : (SRegOffset(rl_src_offset.s_reg_low) + push_offset));
buzbee2700f7e2014-03-07 09:46:20 -0800760 LoadWordDisp(TargetReg(kSp), srcOffsetSp, rs_rSI);
Vladimir Marko70b797d2013-12-03 15:25:24 +0000761 NewLIR4(kX86LockCmpxchg8bA, rDI, rSI, 0, 0);
Razvan A Lupusoru99ad7232014-02-25 17:41:08 -0800762
763 // After a store we need to insert barrier in case of potential load. Since the
764 // locked cmpxchg has full barrier semantics, only a scheduling barrier will be generated.
765 GenMemBarrier(kStoreLoad);
766
Vladimir Marko70b797d2013-12-03 15:25:24 +0000767 FreeTemp(rSI);
768 UnmarkTemp(rSI);
769 NewLIR1(kX86Pop32R, rSI);
770 FreeTemp(rDI);
771 UnmarkTemp(rDI);
772 NewLIR1(kX86Pop32R, rDI);
773 FreeCallTemps();
Vladimir Markoc29bb612013-11-27 16:47:25 +0000774 } else {
775 // EAX must hold expected for CMPXCHG. Neither rl_new_value, nor r_ptr may be in EAX.
buzbee2700f7e2014-03-07 09:46:20 -0800776 FlushReg(rs_r0);
777 LockTemp(rs_r0);
Vladimir Markoc29bb612013-11-27 16:47:25 +0000778
Vladimir Markoc29bb612013-11-27 16:47:25 +0000779 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
780 RegLocation rl_new_value = LoadValue(rl_src_new_value, kCoreReg);
781
782 if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
783 // Mark card for object assuming new value is stored.
784 FreeTemp(r0); // Temporarily release EAX for MarkGCCard().
buzbee2700f7e2014-03-07 09:46:20 -0800785 MarkGCCard(rl_new_value.reg, rl_object.reg);
Vladimir Markoc29bb612013-11-27 16:47:25 +0000786 LockTemp(r0);
787 }
788
789 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
buzbee2700f7e2014-03-07 09:46:20 -0800790 LoadValueDirect(rl_src_expected, rs_r0);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000791 NewLIR5(kX86LockCmpxchgAR, rl_object.reg.GetReg(), rl_offset.reg.GetReg(), 0, 0, rl_new_value.reg.GetReg());
Vladimir Markoc29bb612013-11-27 16:47:25 +0000792
Razvan A Lupusoru99ad7232014-02-25 17:41:08 -0800793 // After a store we need to insert barrier in case of potential load. Since the
794 // locked cmpxchg has full barrier semantics, only a scheduling barrier will be generated.
795 GenMemBarrier(kStoreLoad);
796
Vladimir Markoc29bb612013-11-27 16:47:25 +0000797 FreeTemp(r0);
798 }
799
800 // Convert ZF to boolean
801 RegLocation rl_dest = InlineTarget(info); // boolean place for result
802 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000803 NewLIR2(kX86Set8R, rl_result.reg.GetReg(), kX86CondZ);
804 NewLIR2(kX86Movzx8RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
Vladimir Markoc29bb612013-11-27 16:47:25 +0000805 StoreValue(rl_dest, rl_result);
806 return true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700807}
808
buzbee2700f7e2014-03-07 09:46:20 -0800809LIR* X86Mir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
Mark Mendell55d0eac2014-02-06 11:02:52 -0800810 CHECK(base_of_code_ != nullptr);
811
812 // Address the start of the method
813 RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
814 LoadValueDirectFixed(rl_method, reg);
815 store_method_addr_used_ = true;
816
817 // Load the proper value from the literal area.
818 // We don't know the proper offset for the value, so pick one that will force
819 // 4 byte offset. We will fix this up in the assembler later to have the right
820 // value.
buzbee2700f7e2014-03-07 09:46:20 -0800821 LIR *res = RawLIR(current_dalvik_offset_, kX86Mov32RM, reg.GetReg(), reg.GetReg(), 256,
822 0, 0, target);
Mark Mendell55d0eac2014-02-06 11:02:52 -0800823 res->target = target;
824 res->flags.fixup = kFixupLoad;
825 SetMemRefType(res, true, kLiteral);
826 store_method_addr_used_ = true;
827 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700828}
829
buzbee2700f7e2014-03-07 09:46:20 -0800830LIR* X86Mir2Lir::OpVldm(RegStorage r_base, int count) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700831 LOG(FATAL) << "Unexpected use of OpVldm for x86";
832 return NULL;
833}
834
buzbee2700f7e2014-03-07 09:46:20 -0800835LIR* X86Mir2Lir::OpVstm(RegStorage r_base, int count) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700836 LOG(FATAL) << "Unexpected use of OpVstm for x86";
837 return NULL;
838}
839
840void X86Mir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
841 RegLocation rl_result, int lit,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700842 int first_bit, int second_bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800843 RegStorage t_reg = AllocTemp();
844 OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit);
845 OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700846 FreeTemp(t_reg);
847 if (first_bit != 0) {
buzbee2700f7e2014-03-07 09:46:20 -0800848 OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700849 }
850}
851
Mingyao Yange643a172014-04-08 11:02:52 -0700852void X86Mir2Lir::GenDivZeroCheckWide(RegStorage reg) {
buzbee2700f7e2014-03-07 09:46:20 -0800853 DCHECK(reg.IsPair()); // TODO: allow 64BitSolo.
854 // We are not supposed to clobber the incoming storage, so allocate a temporary.
855 RegStorage t_reg = AllocTemp();
Razvan A Lupusoru090dd442013-12-20 14:35:03 -0800856
857 // Doing an OR is a quick way to check if both registers are zero. This will set the flags.
buzbee2700f7e2014-03-07 09:46:20 -0800858 OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh());
Razvan A Lupusoru090dd442013-12-20 14:35:03 -0800859
860 // In case of zero, throw ArithmeticException.
Mingyao Yange643a172014-04-08 11:02:52 -0700861 GenDivZeroCheck(kCondEq);
Razvan A Lupusoru090dd442013-12-20 14:35:03 -0800862
863 // The temp is no longer needed so free it at this time.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700864 FreeTemp(t_reg);
865}
866
Mingyao Yang80365d92014-04-18 12:10:58 -0700867void X86Mir2Lir::GenArrayBoundsCheck(RegStorage index,
868 RegStorage array_base,
869 int len_offset) {
870 class ArrayBoundsCheckSlowPath : public Mir2Lir::LIRSlowPath {
871 public:
872 ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch,
873 RegStorage index, RegStorage array_base, int32_t len_offset)
874 : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch),
875 index_(index), array_base_(array_base), len_offset_(len_offset) {
876 }
877
878 void Compile() OVERRIDE {
879 m2l_->ResetRegPool();
880 m2l_->ResetDefTracking();
881 GenerateTargetLabel();
882
883 RegStorage new_index = index_;
884 // Move index out of kArg1, either directly to kArg0, or to kArg2.
885 if (index_.GetReg() == m2l_->TargetReg(kArg1).GetReg()) {
886 if (array_base_.GetReg() == m2l_->TargetReg(kArg0).GetReg()) {
887 m2l_->OpRegCopy(m2l_->TargetReg(kArg2), index_);
888 new_index = m2l_->TargetReg(kArg2);
889 } else {
890 m2l_->OpRegCopy(m2l_->TargetReg(kArg0), index_);
891 new_index = m2l_->TargetReg(kArg0);
892 }
893 }
894 // Load array length to kArg1.
895 m2l_->OpRegMem(kOpMov, m2l_->TargetReg(kArg1), array_base_, len_offset_);
896 m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(4, pThrowArrayBounds),
897 new_index, m2l_->TargetReg(kArg1), true);
898 }
899
900 private:
901 const RegStorage index_;
902 const RegStorage array_base_;
903 const int32_t len_offset_;
904 };
905
906 OpRegMem(kOpCmp, index, array_base, len_offset);
907 LIR* branch = OpCondBranch(kCondUge, nullptr);
908 AddSlowPath(new (arena_) ArrayBoundsCheckSlowPath(this, branch,
909 index, array_base, len_offset));
910}
911
912void X86Mir2Lir::GenArrayBoundsCheck(int32_t index,
913 RegStorage array_base,
914 int32_t len_offset) {
915 class ArrayBoundsCheckSlowPath : public Mir2Lir::LIRSlowPath {
916 public:
917 ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch,
918 int32_t index, RegStorage array_base, int32_t len_offset)
919 : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch),
920 index_(index), array_base_(array_base), len_offset_(len_offset) {
921 }
922
923 void Compile() OVERRIDE {
924 m2l_->ResetRegPool();
925 m2l_->ResetDefTracking();
926 GenerateTargetLabel();
927
928 // Load array length to kArg1.
929 m2l_->OpRegMem(kOpMov, m2l_->TargetReg(kArg1), array_base_, len_offset_);
930 m2l_->LoadConstant(m2l_->TargetReg(kArg0), index_);
931 m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(4, pThrowArrayBounds),
932 m2l_->TargetReg(kArg0), m2l_->TargetReg(kArg1), true);
933 }
934
935 private:
936 const int32_t index_;
937 const RegStorage array_base_;
938 const int32_t len_offset_;
939 };
940
941 NewLIR3(IS_SIMM8(index) ? kX86Cmp32MI8 : kX86Cmp32MI, array_base.GetReg(), len_offset, index);
942 LIR* branch = OpCondBranch(kCondLs, nullptr);
943 AddSlowPath(new (arena_) ArrayBoundsCheckSlowPath(this, branch,
944 index, array_base, len_offset));
945}
946
Brian Carlstrom7940e442013-07-12 13:46:57 -0700947// Test suspend flag, return target of taken suspend branch
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700948LIR* X86Mir2Lir::OpTestSuspend(LIR* target) {
Ian Rogersdd7624d2014-03-14 17:43:00 -0700949 OpTlsCmp(Thread::ThreadFlagsOffset<4>(), 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700950 return OpCondBranch((target == NULL) ? kCondNe : kCondEq, target);
951}
952
953// Decrement register and branch on condition
buzbee2700f7e2014-03-07 09:46:20 -0800954LIR* X86Mir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700955 OpRegImm(kOpSub, reg, 1);
Yixin Shoua0dac3e2014-01-23 05:01:22 -0800956 return OpCondBranch(c_code, target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700957}
958
buzbee11b63d12013-08-27 07:34:17 -0700959bool X86Mir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700960 RegLocation rl_src, RegLocation rl_dest, int lit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700961 LOG(FATAL) << "Unexpected use of smallLiteralDive in x86";
962 return false;
963}
964
Ian Rogerse2143c02014-03-28 08:47:16 -0700965bool X86Mir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
966 LOG(FATAL) << "Unexpected use of easyMultiply in x86";
967 return false;
968}
969
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700970LIR* X86Mir2Lir::OpIT(ConditionCode cond, const char* guide) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700971 LOG(FATAL) << "Unexpected use of OpIT in x86";
972 return NULL;
973}
974
Dave Allison3da67a52014-04-02 17:03:45 -0700975void X86Mir2Lir::OpEndIT(LIR* it) {
976 LOG(FATAL) << "Unexpected use of OpEndIT in x86";
977}
978
buzbee2700f7e2014-03-07 09:46:20 -0800979void X86Mir2Lir::GenImulRegImm(RegStorage dest, RegStorage src, int val) {
Mark Mendell4708dcd2014-01-22 09:05:18 -0800980 switch (val) {
981 case 0:
buzbee2700f7e2014-03-07 09:46:20 -0800982 NewLIR2(kX86Xor32RR, dest.GetReg(), dest.GetReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -0800983 break;
984 case 1:
985 OpRegCopy(dest, src);
986 break;
987 default:
988 OpRegRegImm(kOpMul, dest, src, val);
989 break;
990 }
991}
992
buzbee2700f7e2014-03-07 09:46:20 -0800993void X86Mir2Lir::GenImulMemImm(RegStorage dest, int sreg, int displacement, int val) {
Mark Mendell4708dcd2014-01-22 09:05:18 -0800994 LIR *m;
995 switch (val) {
996 case 0:
buzbee2700f7e2014-03-07 09:46:20 -0800997 NewLIR2(kX86Xor32RR, dest.GetReg(), dest.GetReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -0800998 break;
999 case 1:
buzbee695d13a2014-04-19 13:32:20 -07001000 LoadBaseDisp(rs_rX86_SP, displacement, dest, k32, sreg);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001001 break;
1002 default:
buzbee2700f7e2014-03-07 09:46:20 -08001003 m = NewLIR4(IS_SIMM8(val) ? kX86Imul32RMI8 : kX86Imul32RMI, dest.GetReg(), rX86_SP,
Mark Mendell4708dcd2014-01-22 09:05:18 -08001004 displacement, val);
1005 AnnotateDalvikRegAccess(m, displacement >> 2, true /* is_load */, true /* is_64bit */);
1006 break;
1007 }
1008}
1009
Mark Mendelle02d48f2014-01-15 11:19:23 -08001010void X86Mir2Lir::GenMulLong(Instruction::Code, RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001011 RegLocation rl_src2) {
Mark Mendell4708dcd2014-01-22 09:05:18 -08001012 if (rl_src1.is_const) {
1013 std::swap(rl_src1, rl_src2);
1014 }
1015 // Are we multiplying by a constant?
1016 if (rl_src2.is_const) {
1017 // Do special compare/branch against simple const operand
1018 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
1019 if (val == 0) {
1020 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08001021 OpRegReg(kOpXor, rl_result.reg.GetLow(), rl_result.reg.GetLow());
1022 OpRegReg(kOpXor, rl_result.reg.GetHigh(), rl_result.reg.GetHigh());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001023 StoreValueWide(rl_dest, rl_result);
1024 return;
1025 } else if (val == 1) {
Mark Mendell4708dcd2014-01-22 09:05:18 -08001026 StoreValueWide(rl_dest, rl_src1);
1027 return;
1028 } else if (val == 2) {
1029 GenAddLong(Instruction::ADD_LONG, rl_dest, rl_src1, rl_src1);
1030 return;
1031 } else if (IsPowerOfTwo(val)) {
1032 int shift_amount = LowestSetBit(val);
1033 if (!BadOverlap(rl_src1, rl_dest)) {
1034 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
1035 RegLocation rl_result = GenShiftImmOpLong(Instruction::SHL_LONG, rl_dest,
1036 rl_src1, shift_amount);
1037 StoreValueWide(rl_dest, rl_result);
1038 return;
1039 }
1040 }
1041
1042 // Okay, just bite the bullet and do it.
1043 int32_t val_lo = Low32Bits(val);
1044 int32_t val_hi = High32Bits(val);
1045 FlushAllRegs();
1046 LockCallTemps(); // Prepare for explicit register usage.
1047 rl_src1 = UpdateLocWide(rl_src1);
1048 bool src1_in_reg = rl_src1.location == kLocPhysReg;
1049 int displacement = SRegOffset(rl_src1.s_reg_low);
1050
1051 // ECX <- 1H * 2L
1052 // EAX <- 1L * 2H
1053 if (src1_in_reg) {
buzbee2700f7e2014-03-07 09:46:20 -08001054 GenImulRegImm(rs_r1, rl_src1.reg.GetHigh(), val_lo);
1055 GenImulRegImm(rs_r0, rl_src1.reg.GetLow(), val_hi);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001056 } else {
buzbee2700f7e2014-03-07 09:46:20 -08001057 GenImulMemImm(rs_r1, GetSRegHi(rl_src1.s_reg_low), displacement + HIWORD_OFFSET, val_lo);
1058 GenImulMemImm(rs_r0, rl_src1.s_reg_low, displacement + LOWORD_OFFSET, val_hi);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001059 }
1060
1061 // ECX <- ECX + EAX (2H * 1L) + (1H * 2L)
1062 NewLIR2(kX86Add32RR, r1, r0);
1063
1064 // EAX <- 2L
buzbee2700f7e2014-03-07 09:46:20 -08001065 LoadConstantNoClobber(rs_r0, val_lo);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001066
1067 // EDX:EAX <- 2L * 1L (double precision)
1068 if (src1_in_reg) {
buzbee2700f7e2014-03-07 09:46:20 -08001069 NewLIR1(kX86Mul32DaR, rl_src1.reg.GetLowReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001070 } else {
1071 LIR *m = NewLIR2(kX86Mul32DaM, rX86_SP, displacement + LOWORD_OFFSET);
1072 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
1073 true /* is_load */, true /* is_64bit */);
1074 }
1075
1076 // EDX <- EDX + ECX (add high words)
1077 NewLIR2(kX86Add32RR, r2, r1);
1078
1079 // Result is EDX:EAX
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001080 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
buzbee2700f7e2014-03-07 09:46:20 -08001081 RegStorage::MakeRegPair(rs_r0, rs_r2),
Mark Mendell4708dcd2014-01-22 09:05:18 -08001082 INVALID_SREG, INVALID_SREG};
1083 StoreValueWide(rl_dest, rl_result);
1084 return;
1085 }
1086
1087 // Nope. Do it the hard way
Mark Mendellde99bba2014-02-14 12:15:02 -08001088 // Check for V*V. We can eliminate a multiply in that case, as 2L*1H == 2H*1L.
1089 bool is_square = mir_graph_->SRegToVReg(rl_src1.s_reg_low) ==
1090 mir_graph_->SRegToVReg(rl_src2.s_reg_low);
1091
Mark Mendell4708dcd2014-01-22 09:05:18 -08001092 FlushAllRegs();
1093 LockCallTemps(); // Prepare for explicit register usage.
1094 rl_src1 = UpdateLocWide(rl_src1);
1095 rl_src2 = UpdateLocWide(rl_src2);
1096
1097 // At this point, the VRs are in their home locations.
1098 bool src1_in_reg = rl_src1.location == kLocPhysReg;
1099 bool src2_in_reg = rl_src2.location == kLocPhysReg;
1100
1101 // ECX <- 1H
1102 if (src1_in_reg) {
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001103 NewLIR2(kX86Mov32RR, r1, rl_src1.reg.GetHighReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001104 } else {
buzbee2700f7e2014-03-07 09:46:20 -08001105 LoadBaseDisp(rs_rX86_SP, SRegOffset(rl_src1.s_reg_low) + HIWORD_OFFSET, rs_r1,
buzbee695d13a2014-04-19 13:32:20 -07001106 k32, GetSRegHi(rl_src1.s_reg_low));
Mark Mendell4708dcd2014-01-22 09:05:18 -08001107 }
1108
Mark Mendellde99bba2014-02-14 12:15:02 -08001109 if (is_square) {
1110 // Take advantage of the fact that the values are the same.
1111 // ECX <- ECX * 2L (1H * 2L)
1112 if (src2_in_reg) {
buzbee2700f7e2014-03-07 09:46:20 -08001113 NewLIR2(kX86Imul32RR, r1, rl_src2.reg.GetLowReg());
Mark Mendellde99bba2014-02-14 12:15:02 -08001114 } else {
1115 int displacement = SRegOffset(rl_src2.s_reg_low);
1116 LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET);
1117 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
1118 true /* is_load */, true /* is_64bit */);
1119 }
Mark Mendell4708dcd2014-01-22 09:05:18 -08001120
Mark Mendellde99bba2014-02-14 12:15:02 -08001121 // ECX <- 2*ECX (2H * 1L) + (1H * 2L)
1122 NewLIR2(kX86Add32RR, r1, r1);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001123 } else {
Mark Mendellde99bba2014-02-14 12:15:02 -08001124 // EAX <- 2H
1125 if (src2_in_reg) {
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001126 NewLIR2(kX86Mov32RR, r0, rl_src2.reg.GetHighReg());
Mark Mendellde99bba2014-02-14 12:15:02 -08001127 } else {
buzbee2700f7e2014-03-07 09:46:20 -08001128 LoadBaseDisp(rs_rX86_SP, SRegOffset(rl_src2.s_reg_low) + HIWORD_OFFSET, rs_r0,
buzbee695d13a2014-04-19 13:32:20 -07001129 k32, GetSRegHi(rl_src2.s_reg_low));
Mark Mendellde99bba2014-02-14 12:15:02 -08001130 }
Mark Mendell4708dcd2014-01-22 09:05:18 -08001131
Mark Mendellde99bba2014-02-14 12:15:02 -08001132 // EAX <- EAX * 1L (2H * 1L)
1133 if (src1_in_reg) {
buzbee2700f7e2014-03-07 09:46:20 -08001134 NewLIR2(kX86Imul32RR, r0, rl_src1.reg.GetLowReg());
Mark Mendellde99bba2014-02-14 12:15:02 -08001135 } else {
1136 int displacement = SRegOffset(rl_src1.s_reg_low);
1137 LIR *m = NewLIR3(kX86Imul32RM, r0, rX86_SP, displacement + LOWORD_OFFSET);
1138 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
1139 true /* is_load */, true /* is_64bit */);
1140 }
Mark Mendell4708dcd2014-01-22 09:05:18 -08001141
Mark Mendellde99bba2014-02-14 12:15:02 -08001142 // ECX <- ECX * 2L (1H * 2L)
1143 if (src2_in_reg) {
buzbee2700f7e2014-03-07 09:46:20 -08001144 NewLIR2(kX86Imul32RR, r1, rl_src2.reg.GetLowReg());
Mark Mendellde99bba2014-02-14 12:15:02 -08001145 } else {
1146 int displacement = SRegOffset(rl_src2.s_reg_low);
1147 LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET);
1148 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
1149 true /* is_load */, true /* is_64bit */);
1150 }
1151
1152 // ECX <- ECX + EAX (2H * 1L) + (1H * 2L)
1153 NewLIR2(kX86Add32RR, r1, r0);
1154 }
Mark Mendell4708dcd2014-01-22 09:05:18 -08001155
1156 // EAX <- 2L
1157 if (src2_in_reg) {
buzbee2700f7e2014-03-07 09:46:20 -08001158 NewLIR2(kX86Mov32RR, r0, rl_src2.reg.GetLowReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001159 } else {
buzbee2700f7e2014-03-07 09:46:20 -08001160 LoadBaseDisp(rs_rX86_SP, SRegOffset(rl_src2.s_reg_low) + LOWORD_OFFSET, rs_r0,
buzbee695d13a2014-04-19 13:32:20 -07001161 k32, rl_src2.s_reg_low);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001162 }
1163
1164 // EDX:EAX <- 2L * 1L (double precision)
1165 if (src1_in_reg) {
buzbee2700f7e2014-03-07 09:46:20 -08001166 NewLIR1(kX86Mul32DaR, rl_src1.reg.GetLowReg());
Mark Mendell4708dcd2014-01-22 09:05:18 -08001167 } else {
1168 int displacement = SRegOffset(rl_src1.s_reg_low);
1169 LIR *m = NewLIR2(kX86Mul32DaM, rX86_SP, displacement + LOWORD_OFFSET);
1170 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
1171 true /* is_load */, true /* is_64bit */);
1172 }
1173
1174 // EDX <- EDX + ECX (add high words)
1175 NewLIR2(kX86Add32RR, r2, r1);
1176
1177 // Result is EDX:EAX
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001178 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
buzbee2700f7e2014-03-07 09:46:20 -08001179 RegStorage::MakeRegPair(rs_r0, rs_r2), INVALID_SREG, INVALID_SREG};
Mark Mendell4708dcd2014-01-22 09:05:18 -08001180 StoreValueWide(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001181}
Mark Mendelle02d48f2014-01-15 11:19:23 -08001182
1183void X86Mir2Lir::GenLongRegOrMemOp(RegLocation rl_dest, RegLocation rl_src,
1184 Instruction::Code op) {
1185 DCHECK_EQ(rl_dest.location, kLocPhysReg);
1186 X86OpCode x86op = GetOpcode(op, rl_dest, rl_src, false);
1187 if (rl_src.location == kLocPhysReg) {
1188 // Both operands are in registers.
Serguei Katkovab5545f2014-03-25 10:51:15 +07001189 // But we must ensure that rl_src is in pair
1190 rl_src = EvalLocWide(rl_src, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08001191 if (rl_dest.reg.GetLowReg() == rl_src.reg.GetHighReg()) {
Mark Mendelle02d48f2014-01-15 11:19:23 -08001192 // The registers are the same, so we would clobber it before the use.
buzbee2700f7e2014-03-07 09:46:20 -08001193 RegStorage temp_reg = AllocTemp();
1194 OpRegCopy(temp_reg, rl_dest.reg);
1195 rl_src.reg.SetHighReg(temp_reg.GetReg());
Mark Mendelle02d48f2014-01-15 11:19:23 -08001196 }
buzbee2700f7e2014-03-07 09:46:20 -08001197 NewLIR2(x86op, rl_dest.reg.GetLowReg(), rl_src.reg.GetLowReg());
Mark Mendelle02d48f2014-01-15 11:19:23 -08001198
1199 x86op = GetOpcode(op, rl_dest, rl_src, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001200 NewLIR2(x86op, rl_dest.reg.GetHighReg(), rl_src.reg.GetHighReg());
buzbee2700f7e2014-03-07 09:46:20 -08001201 FreeTemp(rl_src.reg);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001202 return;
1203 }
1204
1205 // RHS is in memory.
1206 DCHECK((rl_src.location == kLocDalvikFrame) ||
1207 (rl_src.location == kLocCompilerTemp));
buzbee2700f7e2014-03-07 09:46:20 -08001208 int r_base = TargetReg(kSp).GetReg();
Mark Mendelle02d48f2014-01-15 11:19:23 -08001209 int displacement = SRegOffset(rl_src.s_reg_low);
1210
buzbee2700f7e2014-03-07 09:46:20 -08001211 LIR *lir = NewLIR3(x86op, rl_dest.reg.GetLowReg(), r_base, displacement + LOWORD_OFFSET);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001212 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
1213 true /* is_load */, true /* is64bit */);
1214 x86op = GetOpcode(op, rl_dest, rl_src, true);
buzbee2700f7e2014-03-07 09:46:20 -08001215 lir = NewLIR3(x86op, rl_dest.reg.GetHighReg(), r_base, displacement + HIWORD_OFFSET);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001216 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
1217 true /* is_load */, true /* is64bit */);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001218}
1219
Mark Mendelle02d48f2014-01-15 11:19:23 -08001220void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op) {
1221 rl_dest = UpdateLocWide(rl_dest);
1222 if (rl_dest.location == kLocPhysReg) {
1223 // Ensure we are in a register pair
1224 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
1225
1226 rl_src = UpdateLocWide(rl_src);
1227 GenLongRegOrMemOp(rl_result, rl_src, op);
1228 StoreFinalValueWide(rl_dest, rl_result);
1229 return;
1230 }
1231
1232 // It wasn't in registers, so it better be in memory.
1233 DCHECK((rl_dest.location == kLocDalvikFrame) ||
1234 (rl_dest.location == kLocCompilerTemp));
1235 rl_src = LoadValueWide(rl_src, kCoreReg);
1236
1237 // Operate directly into memory.
1238 X86OpCode x86op = GetOpcode(op, rl_dest, rl_src, false);
buzbee2700f7e2014-03-07 09:46:20 -08001239 int r_base = TargetReg(kSp).GetReg();
Mark Mendelle02d48f2014-01-15 11:19:23 -08001240 int displacement = SRegOffset(rl_dest.s_reg_low);
1241
buzbee2700f7e2014-03-07 09:46:20 -08001242 LIR *lir = NewLIR3(x86op, r_base, displacement + LOWORD_OFFSET, rl_src.reg.GetLowReg());
Mark Mendelle02d48f2014-01-15 11:19:23 -08001243 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
Serguei Katkov217fe732014-03-27 14:41:56 +07001244 true /* is_load */, true /* is64bit */);
1245 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
Mark Mendelle02d48f2014-01-15 11:19:23 -08001246 false /* is_load */, true /* is64bit */);
1247 x86op = GetOpcode(op, rl_dest, rl_src, true);
buzbee2700f7e2014-03-07 09:46:20 -08001248 lir = NewLIR3(x86op, r_base, displacement + HIWORD_OFFSET, rl_src.reg.GetHighReg());
Mark Mendelle02d48f2014-01-15 11:19:23 -08001249 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
Serguei Katkov217fe732014-03-27 14:41:56 +07001250 true /* is_load */, true /* is64bit */);
1251 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
Mark Mendelle02d48f2014-01-15 11:19:23 -08001252 false /* is_load */, true /* is64bit */);
buzbee2700f7e2014-03-07 09:46:20 -08001253 FreeTemp(rl_src.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001254}
1255
Mark Mendelle02d48f2014-01-15 11:19:23 -08001256void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src1,
1257 RegLocation rl_src2, Instruction::Code op,
1258 bool is_commutative) {
1259 // Is this really a 2 operand operation?
1260 switch (op) {
1261 case Instruction::ADD_LONG_2ADDR:
1262 case Instruction::SUB_LONG_2ADDR:
1263 case Instruction::AND_LONG_2ADDR:
1264 case Instruction::OR_LONG_2ADDR:
1265 case Instruction::XOR_LONG_2ADDR:
1266 GenLongArith(rl_dest, rl_src2, op);
1267 return;
1268 default:
1269 break;
1270 }
1271
1272 if (rl_dest.location == kLocPhysReg) {
1273 RegLocation rl_result = LoadValueWide(rl_src1, kCoreReg);
1274
1275 // We are about to clobber the LHS, so it needs to be a temp.
1276 rl_result = ForceTempWide(rl_result);
1277
1278 // Perform the operation using the RHS.
1279 rl_src2 = UpdateLocWide(rl_src2);
1280 GenLongRegOrMemOp(rl_result, rl_src2, op);
1281
1282 // And now record that the result is in the temp.
1283 StoreFinalValueWide(rl_dest, rl_result);
1284 return;
1285 }
1286
1287 // It wasn't in registers, so it better be in memory.
1288 DCHECK((rl_dest.location == kLocDalvikFrame) ||
1289 (rl_dest.location == kLocCompilerTemp));
1290 rl_src1 = UpdateLocWide(rl_src1);
1291 rl_src2 = UpdateLocWide(rl_src2);
1292
1293 // Get one of the source operands into temporary register.
1294 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
buzbee2700f7e2014-03-07 09:46:20 -08001295 if (IsTemp(rl_src1.reg.GetLowReg()) && IsTemp(rl_src1.reg.GetHighReg())) {
Mark Mendelle02d48f2014-01-15 11:19:23 -08001296 GenLongRegOrMemOp(rl_src1, rl_src2, op);
1297 } else if (is_commutative) {
1298 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
1299 // We need at least one of them to be a temporary.
buzbee2700f7e2014-03-07 09:46:20 -08001300 if (!(IsTemp(rl_src2.reg.GetLowReg()) && IsTemp(rl_src2.reg.GetHighReg()))) {
Mark Mendelle02d48f2014-01-15 11:19:23 -08001301 rl_src1 = ForceTempWide(rl_src1);
Yevgeny Rouban91b6ffa2014-03-07 14:35:44 +07001302 GenLongRegOrMemOp(rl_src1, rl_src2, op);
1303 } else {
1304 GenLongRegOrMemOp(rl_src2, rl_src1, op);
1305 StoreFinalValueWide(rl_dest, rl_src2);
1306 return;
Mark Mendelle02d48f2014-01-15 11:19:23 -08001307 }
Mark Mendelle02d48f2014-01-15 11:19:23 -08001308 } else {
1309 // Need LHS to be the temp.
1310 rl_src1 = ForceTempWide(rl_src1);
1311 GenLongRegOrMemOp(rl_src1, rl_src2, op);
1312 }
1313
1314 StoreFinalValueWide(rl_dest, rl_src1);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001315}
1316
Mark Mendelle02d48f2014-01-15 11:19:23 -08001317void X86Mir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001318 RegLocation rl_src1, RegLocation rl_src2) {
Mark Mendelle02d48f2014-01-15 11:19:23 -08001319 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
1320}
1321
1322void X86Mir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest,
1323 RegLocation rl_src1, RegLocation rl_src2) {
1324 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, false);
1325}
1326
1327void X86Mir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest,
1328 RegLocation rl_src1, RegLocation rl_src2) {
1329 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
1330}
1331
1332void X86Mir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest,
1333 RegLocation rl_src1, RegLocation rl_src2) {
1334 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
1335}
1336
1337void X86Mir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest,
1338 RegLocation rl_src1, RegLocation rl_src2) {
1339 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001340}
1341
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001342void X86Mir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
Mark Mendelle02d48f2014-01-15 11:19:23 -08001343 rl_src = LoadValueWide(rl_src, kCoreReg);
1344 RegLocation rl_result = ForceTempWide(rl_src);
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001345 if (((rl_dest.location == kLocPhysReg) && (rl_src.location == kLocPhysReg)) &&
buzbee2700f7e2014-03-07 09:46:20 -08001346 ((rl_dest.reg.GetLowReg() == rl_src.reg.GetHighReg()))) {
Mark Mendelle02d48f2014-01-15 11:19:23 -08001347 // The registers are the same, so we would clobber it before the use.
buzbee2700f7e2014-03-07 09:46:20 -08001348 RegStorage temp_reg = AllocTemp();
1349 OpRegCopy(temp_reg, rl_result.reg);
1350 rl_result.reg.SetHighReg(temp_reg.GetReg());
Mark Mendelle02d48f2014-01-15 11:19:23 -08001351 }
buzbee2700f7e2014-03-07 09:46:20 -08001352 OpRegReg(kOpNeg, rl_result.reg.GetLow(), rl_result.reg.GetLow()); // rLow = -rLow
1353 OpRegImm(kOpAdc, rl_result.reg.GetHigh(), 0); // rHigh = rHigh + CF
1354 OpRegReg(kOpNeg, rl_result.reg.GetHigh(), rl_result.reg.GetHigh()); // rHigh = -rHigh
Brian Carlstrom7940e442013-07-12 13:46:57 -07001355 StoreValueWide(rl_dest, rl_result);
1356}
1357
Ian Rogersdd7624d2014-03-14 17:43:00 -07001358void X86Mir2Lir::OpRegThreadMem(OpKind op, int r_dest, ThreadOffset<4> thread_offset) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001359 X86OpCode opcode = kX86Bkpt;
1360 switch (op) {
1361 case kOpCmp: opcode = kX86Cmp32RT; break;
1362 case kOpMov: opcode = kX86Mov32RT; break;
1363 default:
1364 LOG(FATAL) << "Bad opcode: " << op;
1365 break;
1366 }
Ian Rogers468532e2013-08-05 10:56:33 -07001367 NewLIR2(opcode, r_dest, thread_offset.Int32Value());
Brian Carlstrom7940e442013-07-12 13:46:57 -07001368}
1369
1370/*
1371 * Generate array load
1372 */
1373void X86Mir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
Ian Rogersa9a82542013-10-04 11:17:26 -07001374 RegLocation rl_index, RegLocation rl_dest, int scale) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001375 RegisterClass reg_class = oat_reg_class_by_size(size);
1376 int len_offset = mirror::Array::LengthOffset().Int32Value();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001377 RegLocation rl_result;
1378 rl_array = LoadValue(rl_array, kCoreReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001379
Mark Mendell343adb52013-12-18 06:02:17 -08001380 int data_offset;
buzbee695d13a2014-04-19 13:32:20 -07001381 if (size == k64 || size == kDouble) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001382 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
1383 } else {
1384 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
1385 }
1386
Mark Mendell343adb52013-12-18 06:02:17 -08001387 bool constant_index = rl_index.is_const;
1388 int32_t constant_index_value = 0;
1389 if (!constant_index) {
1390 rl_index = LoadValue(rl_index, kCoreReg);
1391 } else {
1392 constant_index_value = mir_graph_->ConstantValue(rl_index);
1393 // If index is constant, just fold it into the data offset
1394 data_offset += constant_index_value << scale;
1395 // treat as non array below
buzbee2700f7e2014-03-07 09:46:20 -08001396 rl_index.reg = RegStorage::InvalidReg();
Mark Mendell343adb52013-12-18 06:02:17 -08001397 }
1398
Brian Carlstrom7940e442013-07-12 13:46:57 -07001399 /* null object? */
buzbee2700f7e2014-03-07 09:46:20 -08001400 GenNullCheck(rl_array.reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001401
1402 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
Mark Mendell343adb52013-12-18 06:02:17 -08001403 if (constant_index) {
Mingyao Yang80365d92014-04-18 12:10:58 -07001404 GenArrayBoundsCheck(constant_index_value, rl_array.reg, len_offset);
Mark Mendell343adb52013-12-18 06:02:17 -08001405 } else {
Mingyao Yang80365d92014-04-18 12:10:58 -07001406 GenArrayBoundsCheck(rl_index.reg, rl_array.reg, len_offset);
Mark Mendell343adb52013-12-18 06:02:17 -08001407 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07001408 }
Mark Mendell343adb52013-12-18 06:02:17 -08001409 rl_result = EvalLoc(rl_dest, reg_class, true);
buzbee695d13a2014-04-19 13:32:20 -07001410 if ((size == k64) || (size == kDouble)) {
buzbee2700f7e2014-03-07 09:46:20 -08001411 LoadBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_result.reg.GetLow(),
1412 rl_result.reg.GetHigh(), size, INVALID_SREG);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001413 StoreValueWide(rl_dest, rl_result);
1414 } else {
buzbee2700f7e2014-03-07 09:46:20 -08001415 LoadBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_result.reg,
1416 RegStorage::InvalidReg(), size, INVALID_SREG);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001417 StoreValue(rl_dest, rl_result);
1418 }
1419}
1420
1421/*
1422 * Generate array store
1423 *
1424 */
1425void X86Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
Ian Rogersa9a82542013-10-04 11:17:26 -07001426 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001427 RegisterClass reg_class = oat_reg_class_by_size(size);
1428 int len_offset = mirror::Array::LengthOffset().Int32Value();
1429 int data_offset;
1430
buzbee695d13a2014-04-19 13:32:20 -07001431 if (size == k64 || size == kDouble) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001432 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
1433 } else {
1434 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
1435 }
1436
1437 rl_array = LoadValue(rl_array, kCoreReg);
Mark Mendell343adb52013-12-18 06:02:17 -08001438 bool constant_index = rl_index.is_const;
1439 int32_t constant_index_value = 0;
1440 if (!constant_index) {
1441 rl_index = LoadValue(rl_index, kCoreReg);
1442 } else {
1443 // If index is constant, just fold it into the data offset
1444 constant_index_value = mir_graph_->ConstantValue(rl_index);
1445 data_offset += constant_index_value << scale;
1446 // treat as non array below
buzbee2700f7e2014-03-07 09:46:20 -08001447 rl_index.reg = RegStorage::InvalidReg();
Mark Mendell343adb52013-12-18 06:02:17 -08001448 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07001449
1450 /* null object? */
buzbee2700f7e2014-03-07 09:46:20 -08001451 GenNullCheck(rl_array.reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001452
1453 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
Mark Mendell343adb52013-12-18 06:02:17 -08001454 if (constant_index) {
Mingyao Yang80365d92014-04-18 12:10:58 -07001455 GenArrayBoundsCheck(constant_index_value, rl_array.reg, len_offset);
Mark Mendell343adb52013-12-18 06:02:17 -08001456 } else {
Mingyao Yang80365d92014-04-18 12:10:58 -07001457 GenArrayBoundsCheck(rl_index.reg, rl_array.reg, len_offset);
Mark Mendell343adb52013-12-18 06:02:17 -08001458 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07001459 }
buzbee695d13a2014-04-19 13:32:20 -07001460 if ((size == k64) || (size == kDouble)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001461 rl_src = LoadValueWide(rl_src, reg_class);
1462 } else {
1463 rl_src = LoadValue(rl_src, reg_class);
1464 }
1465 // If the src reg can't be byte accessed, move it to a temp first.
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001466 if ((size == kSignedByte || size == kUnsignedByte) && rl_src.reg.GetReg() >= 4) {
buzbee2700f7e2014-03-07 09:46:20 -08001467 RegStorage temp = AllocTemp();
1468 OpRegCopy(temp, rl_src.reg);
1469 StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, temp,
1470 RegStorage::InvalidReg(), size, INVALID_SREG);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001471 } else {
buzbee2700f7e2014-03-07 09:46:20 -08001472 if (rl_src.wide) {
1473 StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_src.reg.GetLow(),
1474 rl_src.reg.GetHigh(), size, INVALID_SREG);
1475 } else {
1476 StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_src.reg,
1477 RegStorage::InvalidReg(), size, INVALID_SREG);
1478 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07001479 }
Ian Rogersa9a82542013-10-04 11:17:26 -07001480 if (card_mark) {
Ian Rogers773aab12013-10-14 13:50:10 -07001481 // Free rl_index if its a temp. Ensures there are 2 free regs for card mark.
Mark Mendell343adb52013-12-18 06:02:17 -08001482 if (!constant_index) {
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001483 FreeTemp(rl_index.reg.GetReg());
Mark Mendell343adb52013-12-18 06:02:17 -08001484 }
buzbee2700f7e2014-03-07 09:46:20 -08001485 MarkGCCard(rl_src.reg, rl_array.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001486 }
1487}
1488
Mark Mendell4708dcd2014-01-22 09:05:18 -08001489RegLocation X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
1490 RegLocation rl_src, int shift_amount) {
1491 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1492 switch (opcode) {
1493 case Instruction::SHL_LONG:
1494 case Instruction::SHL_LONG_2ADDR:
1495 DCHECK_NE(shift_amount, 1); // Prevent a double store from happening.
1496 if (shift_amount == 32) {
buzbee2700f7e2014-03-07 09:46:20 -08001497 OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetLow());
1498 LoadConstant(rl_result.reg.GetLow(), 0);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001499 } else if (shift_amount > 31) {
buzbee2700f7e2014-03-07 09:46:20 -08001500 OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetLow());
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001501 FreeTemp(rl_src.reg.GetHighReg());
1502 NewLIR2(kX86Sal32RI, rl_result.reg.GetHighReg(), shift_amount - 32);
buzbee2700f7e2014-03-07 09:46:20 -08001503 LoadConstant(rl_result.reg.GetLow(), 0);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001504 } else {
buzbee2700f7e2014-03-07 09:46:20 -08001505 OpRegCopy(rl_result.reg, rl_src.reg);
1506 OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
1507 NewLIR3(kX86Shld32RRI, rl_result.reg.GetHighReg(), rl_result.reg.GetLowReg(), shift_amount);
1508 NewLIR2(kX86Sal32RI, rl_result.reg.GetLowReg(), shift_amount);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001509 }
1510 break;
1511 case Instruction::SHR_LONG:
1512 case Instruction::SHR_LONG_2ADDR:
1513 if (shift_amount == 32) {
buzbee2700f7e2014-03-07 09:46:20 -08001514 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetHigh());
1515 OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001516 NewLIR2(kX86Sar32RI, rl_result.reg.GetHighReg(), 31);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001517 } else if (shift_amount > 31) {
buzbee2700f7e2014-03-07 09:46:20 -08001518 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetHigh());
1519 OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
1520 NewLIR2(kX86Sar32RI, rl_result.reg.GetLowReg(), shift_amount - 32);
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001521 NewLIR2(kX86Sar32RI, rl_result.reg.GetHighReg(), 31);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001522 } else {
buzbee2700f7e2014-03-07 09:46:20 -08001523 OpRegCopy(rl_result.reg, rl_src.reg);
1524 OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
1525 NewLIR3(kX86Shrd32RRI, rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg(), shift_amount);
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001526 NewLIR2(kX86Sar32RI, rl_result.reg.GetHighReg(), shift_amount);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001527 }
1528 break;
1529 case Instruction::USHR_LONG:
1530 case Instruction::USHR_LONG_2ADDR:
1531 if (shift_amount == 32) {
buzbee2700f7e2014-03-07 09:46:20 -08001532 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetHigh());
1533 LoadConstant(rl_result.reg.GetHigh(), 0);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001534 } else if (shift_amount > 31) {
buzbee2700f7e2014-03-07 09:46:20 -08001535 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetHigh());
1536 NewLIR2(kX86Shr32RI, rl_result.reg.GetLowReg(), shift_amount - 32);
1537 LoadConstant(rl_result.reg.GetHigh(), 0);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001538 } else {
buzbee2700f7e2014-03-07 09:46:20 -08001539 OpRegCopy(rl_result.reg, rl_src.reg);
1540 OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
1541 NewLIR3(kX86Shrd32RRI, rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg(), shift_amount);
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001542 NewLIR2(kX86Shr32RI, rl_result.reg.GetHighReg(), shift_amount);
Mark Mendell4708dcd2014-01-22 09:05:18 -08001543 }
1544 break;
1545 default:
1546 LOG(FATAL) << "Unexpected case";
1547 }
1548 return rl_result;
1549}
1550
Brian Carlstrom7940e442013-07-12 13:46:57 -07001551void X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
Mark Mendell4708dcd2014-01-22 09:05:18 -08001552 RegLocation rl_src, RegLocation rl_shift) {
1553 // Per spec, we only care about low 6 bits of shift amount.
1554 int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f;
1555 if (shift_amount == 0) {
1556 rl_src = LoadValueWide(rl_src, kCoreReg);
1557 StoreValueWide(rl_dest, rl_src);
1558 return;
1559 } else if (shift_amount == 1 &&
1560 (opcode == Instruction::SHL_LONG || opcode == Instruction::SHL_LONG_2ADDR)) {
1561 // Need to handle this here to avoid calling StoreValueWide twice.
1562 GenAddLong(Instruction::ADD_LONG, rl_dest, rl_src, rl_src);
1563 return;
1564 }
1565 if (BadOverlap(rl_src, rl_dest)) {
1566 GenShiftOpLong(opcode, rl_dest, rl_src, rl_shift);
1567 return;
1568 }
1569 rl_src = LoadValueWide(rl_src, kCoreReg);
1570 RegLocation rl_result = GenShiftImmOpLong(opcode, rl_dest, rl_src, shift_amount);
1571 StoreValueWide(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001572}
1573
1574void X86Mir2Lir::GenArithImmOpLong(Instruction::Code opcode,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001575 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
Mark Mendelle02d48f2014-01-15 11:19:23 -08001576 switch (opcode) {
1577 case Instruction::ADD_LONG:
1578 case Instruction::AND_LONG:
1579 case Instruction::OR_LONG:
1580 case Instruction::XOR_LONG:
1581 if (rl_src2.is_const) {
1582 GenLongLongImm(rl_dest, rl_src1, rl_src2, opcode);
1583 } else {
1584 DCHECK(rl_src1.is_const);
1585 GenLongLongImm(rl_dest, rl_src2, rl_src1, opcode);
1586 }
1587 break;
1588 case Instruction::SUB_LONG:
1589 case Instruction::SUB_LONG_2ADDR:
1590 if (rl_src2.is_const) {
1591 GenLongLongImm(rl_dest, rl_src1, rl_src2, opcode);
1592 } else {
1593 GenSubLong(opcode, rl_dest, rl_src1, rl_src2);
1594 }
1595 break;
1596 case Instruction::ADD_LONG_2ADDR:
1597 case Instruction::OR_LONG_2ADDR:
1598 case Instruction::XOR_LONG_2ADDR:
1599 case Instruction::AND_LONG_2ADDR:
1600 if (rl_src2.is_const) {
1601 GenLongImm(rl_dest, rl_src2, opcode);
1602 } else {
1603 DCHECK(rl_src1.is_const);
1604 GenLongLongImm(rl_dest, rl_src2, rl_src1, opcode);
1605 }
1606 break;
1607 default:
1608 // Default - bail to non-const handler.
1609 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
1610 break;
1611 }
1612}
1613
1614bool X86Mir2Lir::IsNoOp(Instruction::Code op, int32_t value) {
1615 switch (op) {
1616 case Instruction::AND_LONG_2ADDR:
1617 case Instruction::AND_LONG:
1618 return value == -1;
1619 case Instruction::OR_LONG:
1620 case Instruction::OR_LONG_2ADDR:
1621 case Instruction::XOR_LONG:
1622 case Instruction::XOR_LONG_2ADDR:
1623 return value == 0;
1624 default:
1625 return false;
1626 }
1627}
1628
1629X86OpCode X86Mir2Lir::GetOpcode(Instruction::Code op, RegLocation dest, RegLocation rhs,
1630 bool is_high_op) {
1631 bool rhs_in_mem = rhs.location != kLocPhysReg;
1632 bool dest_in_mem = dest.location != kLocPhysReg;
1633 DCHECK(!rhs_in_mem || !dest_in_mem);
1634 switch (op) {
1635 case Instruction::ADD_LONG:
1636 case Instruction::ADD_LONG_2ADDR:
1637 if (dest_in_mem) {
1638 return is_high_op ? kX86Adc32MR : kX86Add32MR;
1639 } else if (rhs_in_mem) {
1640 return is_high_op ? kX86Adc32RM : kX86Add32RM;
1641 }
1642 return is_high_op ? kX86Adc32RR : kX86Add32RR;
1643 case Instruction::SUB_LONG:
1644 case Instruction::SUB_LONG_2ADDR:
1645 if (dest_in_mem) {
1646 return is_high_op ? kX86Sbb32MR : kX86Sub32MR;
1647 } else if (rhs_in_mem) {
1648 return is_high_op ? kX86Sbb32RM : kX86Sub32RM;
1649 }
1650 return is_high_op ? kX86Sbb32RR : kX86Sub32RR;
1651 case Instruction::AND_LONG_2ADDR:
1652 case Instruction::AND_LONG:
1653 if (dest_in_mem) {
1654 return kX86And32MR;
1655 }
1656 return rhs_in_mem ? kX86And32RM : kX86And32RR;
1657 case Instruction::OR_LONG:
1658 case Instruction::OR_LONG_2ADDR:
1659 if (dest_in_mem) {
1660 return kX86Or32MR;
1661 }
1662 return rhs_in_mem ? kX86Or32RM : kX86Or32RR;
1663 case Instruction::XOR_LONG:
1664 case Instruction::XOR_LONG_2ADDR:
1665 if (dest_in_mem) {
1666 return kX86Xor32MR;
1667 }
1668 return rhs_in_mem ? kX86Xor32RM : kX86Xor32RR;
1669 default:
1670 LOG(FATAL) << "Unexpected opcode: " << op;
1671 return kX86Add32RR;
1672 }
1673}
1674
1675X86OpCode X86Mir2Lir::GetOpcode(Instruction::Code op, RegLocation loc, bool is_high_op,
1676 int32_t value) {
1677 bool in_mem = loc.location != kLocPhysReg;
1678 bool byte_imm = IS_SIMM8(value);
buzbee2700f7e2014-03-07 09:46:20 -08001679 DCHECK(in_mem || !IsFpReg(loc.reg));
Mark Mendelle02d48f2014-01-15 11:19:23 -08001680 switch (op) {
1681 case Instruction::ADD_LONG:
1682 case Instruction::ADD_LONG_2ADDR:
1683 if (byte_imm) {
1684 if (in_mem) {
1685 return is_high_op ? kX86Adc32MI8 : kX86Add32MI8;
1686 }
1687 return is_high_op ? kX86Adc32RI8 : kX86Add32RI8;
1688 }
1689 if (in_mem) {
1690 return is_high_op ? kX86Adc32MI : kX86Add32MI;
1691 }
1692 return is_high_op ? kX86Adc32RI : kX86Add32RI;
1693 case Instruction::SUB_LONG:
1694 case Instruction::SUB_LONG_2ADDR:
1695 if (byte_imm) {
1696 if (in_mem) {
1697 return is_high_op ? kX86Sbb32MI8 : kX86Sub32MI8;
1698 }
1699 return is_high_op ? kX86Sbb32RI8 : kX86Sub32RI8;
1700 }
1701 if (in_mem) {
1702 return is_high_op ? kX86Sbb32MI : kX86Sub32MI;
1703 }
1704 return is_high_op ? kX86Sbb32RI : kX86Sub32RI;
1705 case Instruction::AND_LONG_2ADDR:
1706 case Instruction::AND_LONG:
1707 if (byte_imm) {
1708 return in_mem ? kX86And32MI8 : kX86And32RI8;
1709 }
1710 return in_mem ? kX86And32MI : kX86And32RI;
1711 case Instruction::OR_LONG:
1712 case Instruction::OR_LONG_2ADDR:
1713 if (byte_imm) {
1714 return in_mem ? kX86Or32MI8 : kX86Or32RI8;
1715 }
1716 return in_mem ? kX86Or32MI : kX86Or32RI;
1717 case Instruction::XOR_LONG:
1718 case Instruction::XOR_LONG_2ADDR:
1719 if (byte_imm) {
1720 return in_mem ? kX86Xor32MI8 : kX86Xor32RI8;
1721 }
1722 return in_mem ? kX86Xor32MI : kX86Xor32RI;
1723 default:
1724 LOG(FATAL) << "Unexpected opcode: " << op;
1725 return kX86Add32MI;
1726 }
1727}
1728
1729void X86Mir2Lir::GenLongImm(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op) {
1730 DCHECK(rl_src.is_const);
1731 int64_t val = mir_graph_->ConstantValueWide(rl_src);
1732 int32_t val_lo = Low32Bits(val);
1733 int32_t val_hi = High32Bits(val);
1734 rl_dest = UpdateLocWide(rl_dest);
1735
1736 // Can we just do this into memory?
1737 if ((rl_dest.location == kLocDalvikFrame) ||
1738 (rl_dest.location == kLocCompilerTemp)) {
buzbee2700f7e2014-03-07 09:46:20 -08001739 int r_base = TargetReg(kSp).GetReg();
Mark Mendelle02d48f2014-01-15 11:19:23 -08001740 int displacement = SRegOffset(rl_dest.s_reg_low);
1741
1742 if (!IsNoOp(op, val_lo)) {
1743 X86OpCode x86op = GetOpcode(op, rl_dest, false, val_lo);
buzbee2700f7e2014-03-07 09:46:20 -08001744 LIR *lir = NewLIR3(x86op, r_base, displacement + LOWORD_OFFSET, val_lo);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001745 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
Serguei Katkov217fe732014-03-27 14:41:56 +07001746 true /* is_load */, true /* is64bit */);
1747 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
Mark Mendelle02d48f2014-01-15 11:19:23 -08001748 false /* is_load */, true /* is64bit */);
1749 }
1750 if (!IsNoOp(op, val_hi)) {
1751 X86OpCode x86op = GetOpcode(op, rl_dest, true, val_hi);
buzbee2700f7e2014-03-07 09:46:20 -08001752 LIR *lir = NewLIR3(x86op, r_base, displacement + HIWORD_OFFSET, val_hi);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001753 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
Serguei Katkov217fe732014-03-27 14:41:56 +07001754 true /* is_load */, true /* is64bit */);
1755 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
Mark Mendelle02d48f2014-01-15 11:19:23 -08001756 false /* is_load */, true /* is64bit */);
1757 }
1758 return;
1759 }
1760
1761 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
1762 DCHECK_EQ(rl_result.location, kLocPhysReg);
buzbee2700f7e2014-03-07 09:46:20 -08001763 DCHECK(!IsFpReg(rl_result.reg));
Mark Mendelle02d48f2014-01-15 11:19:23 -08001764
1765 if (!IsNoOp(op, val_lo)) {
1766 X86OpCode x86op = GetOpcode(op, rl_result, false, val_lo);
buzbee2700f7e2014-03-07 09:46:20 -08001767 NewLIR2(x86op, rl_result.reg.GetLowReg(), val_lo);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001768 }
1769 if (!IsNoOp(op, val_hi)) {
1770 X86OpCode x86op = GetOpcode(op, rl_result, true, val_hi);
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001771 NewLIR2(x86op, rl_result.reg.GetHighReg(), val_hi);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001772 }
1773 StoreValueWide(rl_dest, rl_result);
1774}
1775
1776void X86Mir2Lir::GenLongLongImm(RegLocation rl_dest, RegLocation rl_src1,
1777 RegLocation rl_src2, Instruction::Code op) {
1778 DCHECK(rl_src2.is_const);
1779 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
1780 int32_t val_lo = Low32Bits(val);
1781 int32_t val_hi = High32Bits(val);
1782 rl_dest = UpdateLocWide(rl_dest);
1783 rl_src1 = UpdateLocWide(rl_src1);
1784
1785 // Can we do this directly into the destination registers?
1786 if (rl_dest.location == kLocPhysReg && rl_src1.location == kLocPhysReg &&
buzbee2700f7e2014-03-07 09:46:20 -08001787 rl_dest.reg.GetLowReg() == rl_src1.reg.GetLowReg() &&
1788 rl_dest.reg.GetHighReg() == rl_src1.reg.GetHighReg() &&
1789 !IsFpReg(rl_dest.reg)) {
Mark Mendelle02d48f2014-01-15 11:19:23 -08001790 if (!IsNoOp(op, val_lo)) {
1791 X86OpCode x86op = GetOpcode(op, rl_dest, false, val_lo);
buzbee2700f7e2014-03-07 09:46:20 -08001792 NewLIR2(x86op, rl_dest.reg.GetLowReg(), val_lo);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001793 }
1794 if (!IsNoOp(op, val_hi)) {
1795 X86OpCode x86op = GetOpcode(op, rl_dest, true, val_hi);
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001796 NewLIR2(x86op, rl_dest.reg.GetHighReg(), val_hi);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001797 }
Maxim Kazantsev653f2bf2014-02-13 15:11:17 +07001798
1799 StoreFinalValueWide(rl_dest, rl_dest);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001800 return;
1801 }
1802
1803 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
1804 DCHECK_EQ(rl_src1.location, kLocPhysReg);
1805
1806 // We need the values to be in a temporary
1807 RegLocation rl_result = ForceTempWide(rl_src1);
1808 if (!IsNoOp(op, val_lo)) {
1809 X86OpCode x86op = GetOpcode(op, rl_result, false, val_lo);
buzbee2700f7e2014-03-07 09:46:20 -08001810 NewLIR2(x86op, rl_result.reg.GetLowReg(), val_lo);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001811 }
1812 if (!IsNoOp(op, val_hi)) {
1813 X86OpCode x86op = GetOpcode(op, rl_result, true, val_hi);
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001814 NewLIR2(x86op, rl_result.reg.GetHighReg(), val_hi);
Mark Mendelle02d48f2014-01-15 11:19:23 -08001815 }
1816
1817 StoreFinalValueWide(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001818}
1819
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001820// For final classes there are no sub-classes to check and so we can answer the instance-of
1821// question with simple comparisons. Use compares to memory and SETEQ to optimize for x86.
1822void X86Mir2Lir::GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx,
1823 RegLocation rl_dest, RegLocation rl_src) {
1824 RegLocation object = LoadValue(rl_src, kCoreReg);
1825 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08001826 RegStorage result_reg = rl_result.reg;
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001827
1828 // SETcc only works with EAX..EDX.
buzbee2700f7e2014-03-07 09:46:20 -08001829 if (result_reg == object.reg || result_reg.GetReg() >= 4) {
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001830 result_reg = AllocTypedTemp(false, kCoreReg);
buzbee2700f7e2014-03-07 09:46:20 -08001831 DCHECK_LT(result_reg.GetReg(), 4);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001832 }
1833
1834 // Assume that there is no match.
1835 LoadConstant(result_reg, 0);
buzbee2700f7e2014-03-07 09:46:20 -08001836 LIR* null_branchover = OpCmpImmBranch(kCondEq, object.reg, 0, NULL);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001837
buzbee2700f7e2014-03-07 09:46:20 -08001838 RegStorage check_class = AllocTypedTemp(false, kCoreReg);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001839
1840 // If Method* is already in a register, we can save a copy.
1841 RegLocation rl_method = mir_graph_->GetMethodLoc();
1842 int32_t offset_of_type = mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
1843 (sizeof(mirror::Class*) * type_idx);
1844
1845 if (rl_method.location == kLocPhysReg) {
1846 if (use_declaring_class) {
buzbee695d13a2014-04-19 13:32:20 -07001847 LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001848 check_class);
1849 } else {
buzbee695d13a2014-04-19 13:32:20 -07001850 LoadRefDisp(rl_method.reg, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001851 check_class);
buzbee695d13a2014-04-19 13:32:20 -07001852 LoadRefDisp(check_class, offset_of_type, check_class);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001853 }
1854 } else {
1855 LoadCurrMethodDirect(check_class);
1856 if (use_declaring_class) {
buzbee695d13a2014-04-19 13:32:20 -07001857 LoadRefDisp(check_class, mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001858 check_class);
1859 } else {
buzbee695d13a2014-04-19 13:32:20 -07001860 LoadRefDisp(check_class, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001861 check_class);
buzbee695d13a2014-04-19 13:32:20 -07001862 LoadRefDisp(check_class, offset_of_type, check_class);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001863 }
1864 }
1865
1866 // Compare the computed class to the class in the object.
1867 DCHECK_EQ(object.location, kLocPhysReg);
buzbee2700f7e2014-03-07 09:46:20 -08001868 OpRegMem(kOpCmp, check_class, object.reg, mirror::Object::ClassOffset().Int32Value());
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001869
1870 // Set the low byte of the result to 0 or 1 from the compare condition code.
buzbee2700f7e2014-03-07 09:46:20 -08001871 NewLIR2(kX86Set8R, result_reg.GetReg(), kX86CondEq);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001872
1873 LIR* target = NewLIR0(kPseudoTargetLabel);
1874 null_branchover->target = target;
1875 FreeTemp(check_class);
1876 if (IsTemp(result_reg)) {
buzbee2700f7e2014-03-07 09:46:20 -08001877 OpRegCopy(rl_result.reg, result_reg);
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001878 FreeTemp(result_reg);
1879 }
1880 StoreValue(rl_dest, rl_result);
1881}
1882
Mark Mendell6607d972014-02-10 06:54:18 -08001883void X86Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
1884 bool type_known_abstract, bool use_declaring_class,
1885 bool can_assume_type_is_in_dex_cache,
1886 uint32_t type_idx, RegLocation rl_dest,
1887 RegLocation rl_src) {
1888 FlushAllRegs();
1889 // May generate a call - use explicit registers.
1890 LockCallTemps();
1891 LoadCurrMethodDirect(TargetReg(kArg1)); // kArg1 gets current Method*.
buzbee2700f7e2014-03-07 09:46:20 -08001892 RegStorage class_reg = TargetReg(kArg2); // kArg2 will hold the Class*.
Mark Mendell6607d972014-02-10 06:54:18 -08001893 // Reference must end up in kArg0.
1894 if (needs_access_check) {
1895 // Check we have access to type_idx and if not throw IllegalAccessError,
1896 // Caller function returns Class* in kArg0.
Ian Rogersdd7624d2014-03-14 17:43:00 -07001897 CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(4, pInitializeTypeAndVerifyAccess),
Mark Mendell6607d972014-02-10 06:54:18 -08001898 type_idx, true);
1899 OpRegCopy(class_reg, TargetReg(kRet0));
1900 LoadValueDirectFixed(rl_src, TargetReg(kArg0));
1901 } else if (use_declaring_class) {
1902 LoadValueDirectFixed(rl_src, TargetReg(kArg0));
buzbee695d13a2014-04-19 13:32:20 -07001903 LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
buzbee2700f7e2014-03-07 09:46:20 -08001904 class_reg);
Mark Mendell6607d972014-02-10 06:54:18 -08001905 } else {
1906 // Load dex cache entry into class_reg (kArg2).
1907 LoadValueDirectFixed(rl_src, TargetReg(kArg0));
buzbee695d13a2014-04-19 13:32:20 -07001908 LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
buzbee2700f7e2014-03-07 09:46:20 -08001909 class_reg);
Mark Mendell6607d972014-02-10 06:54:18 -08001910 int32_t offset_of_type =
1911 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
1912 * type_idx);
buzbee695d13a2014-04-19 13:32:20 -07001913 LoadRefDisp(class_reg, offset_of_type, class_reg);
Mark Mendell6607d972014-02-10 06:54:18 -08001914 if (!can_assume_type_is_in_dex_cache) {
1915 // Need to test presence of type in dex cache at runtime.
1916 LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
1917 // Type is not resolved. Call out to helper, which will return resolved type in kRet0/kArg0.
Ian Rogersdd7624d2014-03-14 17:43:00 -07001918 CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(4, pInitializeType), type_idx, true);
Mark Mendell6607d972014-02-10 06:54:18 -08001919 OpRegCopy(TargetReg(kArg2), TargetReg(kRet0)); // Align usage with fast path.
1920 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); /* Reload Ref. */
1921 // Rejoin code paths
1922 LIR* hop_target = NewLIR0(kPseudoTargetLabel);
1923 hop_branch->target = hop_target;
1924 }
1925 }
1926 /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result. */
1927 RegLocation rl_result = GetReturn(false);
1928
1929 // SETcc only works with EAX..EDX.
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001930 DCHECK_LT(rl_result.reg.GetReg(), 4);
Mark Mendell6607d972014-02-10 06:54:18 -08001931
1932 // Is the class NULL?
1933 LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
1934
1935 /* Load object->klass_. */
1936 DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
buzbee695d13a2014-04-19 13:32:20 -07001937 LoadRefDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
Mark Mendell6607d972014-02-10 06:54:18 -08001938 /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class. */
1939 LIR* branchover = nullptr;
1940 if (type_known_final) {
1941 // Ensure top 3 bytes of result are 0.
buzbee2700f7e2014-03-07 09:46:20 -08001942 LoadConstant(rl_result.reg, 0);
Mark Mendell6607d972014-02-10 06:54:18 -08001943 OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2));
1944 // Set the low byte of the result to 0 or 1 from the compare condition code.
Bill Buzbee00e1ec62014-02-27 23:44:13 +00001945 NewLIR2(kX86Set8R, rl_result.reg.GetReg(), kX86CondEq);
Mark Mendell6607d972014-02-10 06:54:18 -08001946 } else {
1947 if (!type_known_abstract) {
buzbee2700f7e2014-03-07 09:46:20 -08001948 LoadConstant(rl_result.reg, 1); // Assume result succeeds.
Mark Mendell6607d972014-02-10 06:54:18 -08001949 branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
1950 }
1951 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
Ian Rogersdd7624d2014-03-14 17:43:00 -07001952 OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(4, pInstanceofNonTrivial));
Mark Mendell6607d972014-02-10 06:54:18 -08001953 }
1954 // TODO: only clobber when type isn't final?
1955 ClobberCallerSave();
1956 /* Branch targets here. */
1957 LIR* target = NewLIR0(kPseudoTargetLabel);
1958 StoreValue(rl_dest, rl_result);
1959 branch1->target = target;
1960 if (branchover != nullptr) {
1961 branchover->target = target;
1962 }
1963}
1964
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08001965void X86Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,
1966 RegLocation rl_lhs, RegLocation rl_rhs) {
1967 OpKind op = kOpBkpt;
1968 bool is_div_rem = false;
1969 bool unary = false;
1970 bool shift_op = false;
1971 bool is_two_addr = false;
1972 RegLocation rl_result;
1973 switch (opcode) {
1974 case Instruction::NEG_INT:
1975 op = kOpNeg;
1976 unary = true;
1977 break;
1978 case Instruction::NOT_INT:
1979 op = kOpMvn;
1980 unary = true;
1981 break;
1982 case Instruction::ADD_INT_2ADDR:
1983 is_two_addr = true;
1984 // Fallthrough
1985 case Instruction::ADD_INT:
1986 op = kOpAdd;
1987 break;
1988 case Instruction::SUB_INT_2ADDR:
1989 is_two_addr = true;
1990 // Fallthrough
1991 case Instruction::SUB_INT:
1992 op = kOpSub;
1993 break;
1994 case Instruction::MUL_INT_2ADDR:
1995 is_two_addr = true;
1996 // Fallthrough
1997 case Instruction::MUL_INT:
1998 op = kOpMul;
1999 break;
2000 case Instruction::DIV_INT_2ADDR:
2001 is_two_addr = true;
2002 // Fallthrough
2003 case Instruction::DIV_INT:
2004 op = kOpDiv;
2005 is_div_rem = true;
2006 break;
2007 /* NOTE: returns in kArg1 */
2008 case Instruction::REM_INT_2ADDR:
2009 is_two_addr = true;
2010 // Fallthrough
2011 case Instruction::REM_INT:
2012 op = kOpRem;
2013 is_div_rem = true;
2014 break;
2015 case Instruction::AND_INT_2ADDR:
2016 is_two_addr = true;
2017 // Fallthrough
2018 case Instruction::AND_INT:
2019 op = kOpAnd;
2020 break;
2021 case Instruction::OR_INT_2ADDR:
2022 is_two_addr = true;
2023 // Fallthrough
2024 case Instruction::OR_INT:
2025 op = kOpOr;
2026 break;
2027 case Instruction::XOR_INT_2ADDR:
2028 is_two_addr = true;
2029 // Fallthrough
2030 case Instruction::XOR_INT:
2031 op = kOpXor;
2032 break;
2033 case Instruction::SHL_INT_2ADDR:
2034 is_two_addr = true;
2035 // Fallthrough
2036 case Instruction::SHL_INT:
2037 shift_op = true;
2038 op = kOpLsl;
2039 break;
2040 case Instruction::SHR_INT_2ADDR:
2041 is_two_addr = true;
2042 // Fallthrough
2043 case Instruction::SHR_INT:
2044 shift_op = true;
2045 op = kOpAsr;
2046 break;
2047 case Instruction::USHR_INT_2ADDR:
2048 is_two_addr = true;
2049 // Fallthrough
2050 case Instruction::USHR_INT:
2051 shift_op = true;
2052 op = kOpLsr;
2053 break;
2054 default:
2055 LOG(FATAL) << "Invalid word arith op: " << opcode;
2056 }
2057
2058 // Can we convert to a two address instruction?
2059 if (!is_two_addr &&
2060 (mir_graph_->SRegToVReg(rl_dest.s_reg_low) ==
2061 mir_graph_->SRegToVReg(rl_lhs.s_reg_low))) {
2062 is_two_addr = true;
2063 }
2064
2065 // Get the div/rem stuff out of the way.
2066 if (is_div_rem) {
2067 rl_result = GenDivRem(rl_dest, rl_lhs, rl_rhs, op == kOpDiv, true);
2068 StoreValue(rl_dest, rl_result);
2069 return;
2070 }
2071
2072 if (unary) {
2073 rl_lhs = LoadValue(rl_lhs, kCoreReg);
2074 rl_result = UpdateLoc(rl_dest);
2075 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08002076 OpRegReg(op, rl_result.reg, rl_lhs.reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002077 } else {
2078 if (shift_op) {
2079 // X86 doesn't require masking and must use ECX.
buzbee2700f7e2014-03-07 09:46:20 -08002080 RegStorage t_reg = TargetReg(kCount); // rCX
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002081 LoadValueDirectFixed(rl_rhs, t_reg);
2082 if (is_two_addr) {
2083 // Can we do this directly into memory?
2084 rl_result = UpdateLoc(rl_dest);
2085 rl_rhs = LoadValue(rl_rhs, kCoreReg);
2086 if (rl_result.location != kLocPhysReg) {
2087 // Okay, we can do this into memory
buzbee2700f7e2014-03-07 09:46:20 -08002088 OpMemReg(op, rl_result, t_reg.GetReg());
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002089 FreeTemp(t_reg);
2090 return;
Bill Buzbee00e1ec62014-02-27 23:44:13 +00002091 } else if (!IsFpReg(rl_result.reg.GetReg())) {
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002092 // Can do this directly into the result register
buzbee2700f7e2014-03-07 09:46:20 -08002093 OpRegReg(op, rl_result.reg, t_reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002094 FreeTemp(t_reg);
2095 StoreFinalValue(rl_dest, rl_result);
2096 return;
2097 }
2098 }
2099 // Three address form, or we can't do directly.
2100 rl_lhs = LoadValue(rl_lhs, kCoreReg);
2101 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08002102 OpRegRegReg(op, rl_result.reg, rl_lhs.reg, t_reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002103 FreeTemp(t_reg);
2104 } else {
2105 // Multiply is 3 operand only (sort of).
2106 if (is_two_addr && op != kOpMul) {
2107 // Can we do this directly into memory?
2108 rl_result = UpdateLoc(rl_dest);
2109 if (rl_result.location == kLocPhysReg) {
Serguei Katkov366f8ae2014-04-15 16:55:26 +07002110 // Ensure res is in a core reg
2111 rl_result = EvalLoc(rl_dest, kCoreReg, true);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002112 // Can we do this from memory directly?
2113 rl_rhs = UpdateLoc(rl_rhs);
2114 if (rl_rhs.location != kLocPhysReg) {
buzbee2700f7e2014-03-07 09:46:20 -08002115 OpRegMem(op, rl_result.reg, rl_rhs);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002116 StoreFinalValue(rl_dest, rl_result);
2117 return;
buzbee2700f7e2014-03-07 09:46:20 -08002118 } else if (!IsFpReg(rl_rhs.reg)) {
2119 OpRegReg(op, rl_result.reg, rl_rhs.reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002120 StoreFinalValue(rl_dest, rl_result);
2121 return;
2122 }
2123 }
2124 rl_rhs = LoadValue(rl_rhs, kCoreReg);
2125 if (rl_result.location != kLocPhysReg) {
2126 // Okay, we can do this into memory.
Bill Buzbee00e1ec62014-02-27 23:44:13 +00002127 OpMemReg(op, rl_result, rl_rhs.reg.GetReg());
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002128 return;
buzbee2700f7e2014-03-07 09:46:20 -08002129 } else if (!IsFpReg(rl_result.reg)) {
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002130 // Can do this directly into the result register.
buzbee2700f7e2014-03-07 09:46:20 -08002131 OpRegReg(op, rl_result.reg, rl_rhs.reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002132 StoreFinalValue(rl_dest, rl_result);
2133 return;
2134 } else {
2135 rl_lhs = LoadValue(rl_lhs, kCoreReg);
2136 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08002137 OpRegRegReg(op, rl_result.reg, rl_lhs.reg, rl_rhs.reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002138 }
2139 } else {
2140 // Try to use reg/memory instructions.
2141 rl_lhs = UpdateLoc(rl_lhs);
2142 rl_rhs = UpdateLoc(rl_rhs);
2143 // We can't optimize with FP registers.
2144 if (!IsOperationSafeWithoutTemps(rl_lhs, rl_rhs)) {
2145 // Something is difficult, so fall back to the standard case.
2146 rl_lhs = LoadValue(rl_lhs, kCoreReg);
2147 rl_rhs = LoadValue(rl_rhs, kCoreReg);
2148 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08002149 OpRegRegReg(op, rl_result.reg, rl_lhs.reg, rl_rhs.reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002150 } else {
2151 // We can optimize by moving to result and using memory operands.
2152 if (rl_rhs.location != kLocPhysReg) {
2153 // Force LHS into result.
Serguei Katkov66da1362014-03-14 13:33:33 +07002154 // We should be careful with order here
2155 // If rl_dest and rl_lhs points to the same VR we should load first
2156 // If the are different we should find a register first for dest
2157 if (mir_graph_->SRegToVReg(rl_dest.s_reg_low) == mir_graph_->SRegToVReg(rl_lhs.s_reg_low)) {
2158 rl_lhs = LoadValue(rl_lhs, kCoreReg);
2159 rl_result = EvalLoc(rl_dest, kCoreReg, true);
2160 } else {
2161 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08002162 LoadValueDirect(rl_lhs, rl_result.reg);
Serguei Katkov66da1362014-03-14 13:33:33 +07002163 }
buzbee2700f7e2014-03-07 09:46:20 -08002164 OpRegMem(op, rl_result.reg, rl_rhs);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002165 } else if (rl_lhs.location != kLocPhysReg) {
2166 // RHS is in a register; LHS is in memory.
2167 if (op != kOpSub) {
2168 // Force RHS into result and operate on memory.
2169 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08002170 OpRegCopy(rl_result.reg, rl_rhs.reg);
2171 OpRegMem(op, rl_result.reg, rl_lhs);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002172 } else {
2173 // Subtraction isn't commutative.
2174 rl_lhs = LoadValue(rl_lhs, kCoreReg);
2175 rl_rhs = LoadValue(rl_rhs, kCoreReg);
2176 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08002177 OpRegRegReg(op, rl_result.reg, rl_lhs.reg, rl_rhs.reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002178 }
2179 } else {
2180 // Both are in registers.
2181 rl_lhs = LoadValue(rl_lhs, kCoreReg);
2182 rl_rhs = LoadValue(rl_rhs, kCoreReg);
2183 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -08002184 OpRegRegReg(op, rl_result.reg, rl_lhs.reg, rl_rhs.reg);
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002185 }
2186 }
2187 }
2188 }
2189 }
2190 StoreValue(rl_dest, rl_result);
2191}
2192
2193bool X86Mir2Lir::IsOperationSafeWithoutTemps(RegLocation rl_lhs, RegLocation rl_rhs) {
2194 // If we have non-core registers, then we can't do good things.
Bill Buzbee00e1ec62014-02-27 23:44:13 +00002195 if (rl_lhs.location == kLocPhysReg && IsFpReg(rl_lhs.reg.GetReg())) {
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002196 return false;
2197 }
Bill Buzbee00e1ec62014-02-27 23:44:13 +00002198 if (rl_rhs.location == kLocPhysReg && IsFpReg(rl_rhs.reg.GetReg())) {
Mark Mendellfeb2b4e2014-01-28 12:59:49 -08002199 return false;
2200 }
2201
2202 // Everything will be fine :-).
2203 return true;
2204}
Brian Carlstrom7940e442013-07-12 13:46:57 -07002205} // namespace art