blob: 3ee3e2e61de8408114113a51ec624a20376683e1 [file] [log] [blame]
Matteo Franchin43ec8732014-03-31 15:00:14 +01001/*
2 * Copyright (C) 2011 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 Thumb2 ISA. */
18
19#include "arm64_lir.h"
20#include "codegen_arm64.h"
21#include "dex/quick/mir_to_lir-inl.h"
buzbeeb5860fb2014-06-21 15:31:01 -070022#include "dex/reg_storage_eq.h"
Matteo Franchin43ec8732014-03-31 15:00:14 +010023#include "entrypoints/quick/quick_entrypoints.h"
24#include "mirror/array.h"
25
26namespace art {
27
28LIR* Arm64Mir2Lir::OpCmpBranch(ConditionCode cond, RegStorage src1, RegStorage src2, LIR* target) {
29 OpRegReg(kOpCmp, src1, src2);
30 return OpCondBranch(cond, target);
31}
32
Matteo Franchin43ec8732014-03-31 15:00:14 +010033LIR* Arm64Mir2Lir::OpIT(ConditionCode ccode, const char* guide) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +010034 LOG(FATAL) << "Unexpected use of OpIT for Arm64";
35 return NULL;
Matteo Franchin43ec8732014-03-31 15:00:14 +010036}
37
38void Arm64Mir2Lir::OpEndIT(LIR* it) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +010039 LOG(FATAL) << "Unexpected use of OpEndIT for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +010040}
41
42/*
43 * 64-bit 3way compare function.
Matteo Franchine45fb9e2014-05-06 10:10:30 +010044 * cmp xA, xB
Zheng Xu511c8a62014-06-03 16:22:23 +080045 * csinc wC, wzr, wzr, eq // wC = (xA == xB) ? 0 : 1
46 * csneg wC, wC, wC, ge // wC = (xA >= xB) ? wC : -wC
Matteo Franchin43ec8732014-03-31 15:00:14 +010047 */
Matteo Franchine45fb9e2014-05-06 10:10:30 +010048void Arm64Mir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1,
49 RegLocation rl_src2) {
50 RegLocation rl_result;
Matteo Franchin43ec8732014-03-31 15:00:14 +010051 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
52 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
Matteo Franchine45fb9e2014-05-06 10:10:30 +010053 rl_result = EvalLoc(rl_dest, kCoreReg, true);
Matteo Franchin43ec8732014-03-31 15:00:14 +010054
Matteo Franchine45fb9e2014-05-06 10:10:30 +010055 OpRegReg(kOpCmp, rl_src1.reg, rl_src2.reg);
Zheng Xu511c8a62014-06-03 16:22:23 +080056 NewLIR4(kA64Csinc4rrrc, rl_result.reg.GetReg(), rwzr, rwzr, kArmCondEq);
57 NewLIR4(kA64Csneg4rrrc, rl_result.reg.GetReg(), rl_result.reg.GetReg(),
58 rl_result.reg.GetReg(), kArmCondGe);
59 StoreValue(rl_dest, rl_result);
Serban Constantinescued65c5e2014-05-22 15:10:18 +010060}
61
62void Arm64Mir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest,
63 RegLocation rl_src1, RegLocation rl_shift) {
64 OpKind op = kOpBkpt;
65 switch (opcode) {
66 case Instruction::SHL_LONG:
67 case Instruction::SHL_LONG_2ADDR:
68 op = kOpLsl;
69 break;
70 case Instruction::SHR_LONG:
71 case Instruction::SHR_LONG_2ADDR:
72 op = kOpAsr;
73 break;
74 case Instruction::USHR_LONG:
75 case Instruction::USHR_LONG_2ADDR:
76 op = kOpLsr;
77 break;
78 default:
79 LOG(FATAL) << "Unexpected case: " << opcode;
80 }
Zheng Xue2eb29e2014-06-12 10:22:33 +080081 rl_shift = LoadValue(rl_shift, kCoreReg);
Serban Constantinescued65c5e2014-05-22 15:10:18 +010082 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
83 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Zheng Xue2eb29e2014-06-12 10:22:33 +080084 OpRegRegReg(op, rl_result.reg, rl_src1.reg, As64BitReg(rl_shift.reg));
Serban Constantinescued65c5e2014-05-22 15:10:18 +010085 StoreValueWide(rl_dest, rl_result);
Matteo Franchin43ec8732014-03-31 15:00:14 +010086}
87
Matteo Franchin43ec8732014-03-31 15:00:14 +010088void Arm64Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
89 RegLocation rl_result;
90 RegLocation rl_src = mir_graph_->GetSrc(mir, 0);
91 RegLocation rl_dest = mir_graph_->GetDest(mir);
buzbeea0cd2d72014-06-01 09:33:49 -070092 RegisterClass src_reg_class = rl_src.ref ? kRefReg : kCoreReg;
93 RegisterClass result_reg_class = rl_dest.ref ? kRefReg : kCoreReg;
Andreas Gampe381f8ac2014-07-10 03:23:41 -070094
buzbeea0cd2d72014-06-01 09:33:49 -070095 rl_src = LoadValue(rl_src, src_reg_class);
Andreas Gampe381f8ac2014-07-10 03:23:41 -070096 // rl_src may be aliased with rl_result/rl_dest, so do compare early.
97 OpRegImm(kOpCmp, rl_src.reg, 0);
98
Serban Constantinescu05e27ff2014-05-28 13:21:45 +010099 ArmConditionCode code = ArmConditionEncoding(mir->meta.ccode);
100
Andreas Gampe381f8ac2014-07-10 03:23:41 -0700101 // The kMirOpSelect has two variants, one for constants and one for moves.
102 bool is_wide = rl_dest.ref || rl_dest.wide;
103
104 if (mir->ssa_rep->num_uses == 1) {
105 uint32_t true_val = mir->dalvikInsn.vB;
106 uint32_t false_val = mir->dalvikInsn.vC;
107
108 int opcode; // The opcode.
109 int left_op, right_op; // The operands.
110 bool rl_result_evaled = false;
111
112 // Check some simple cases.
113 // TODO: Improve this.
114 int zero_reg = (is_wide ? rs_xzr : rs_wzr).GetReg();
115
116 if ((true_val == 0 && false_val == 1) || (true_val == 1 && false_val == 0)) {
117 // CSInc cheap based on wzr.
118 if (true_val == 1) {
119 // Negate.
120 code = ArmConditionEncoding(NegateComparison(mir->meta.ccode));
121 }
122
123 left_op = right_op = zero_reg;
124 opcode = is_wide ? WIDE(kA64Csinc4rrrc) : kA64Csinc4rrrc;
125 } else if ((true_val == 0 && false_val == 0xFFFFFFFF) ||
126 (true_val == 0xFFFFFFFF && false_val == 0)) {
127 // CSneg cheap based on wzr.
128 if (true_val == 0xFFFFFFFF) {
129 // Negate.
130 code = ArmConditionEncoding(NegateComparison(mir->meta.ccode));
131 }
132
133 left_op = right_op = zero_reg;
134 opcode = is_wide ? WIDE(kA64Csneg4rrrc) : kA64Csneg4rrrc;
135 } else if (true_val == 0 || false_val == 0) {
136 // Csel half cheap based on wzr.
137 rl_result = EvalLoc(rl_dest, result_reg_class, true);
138 rl_result_evaled = true;
139 if (false_val == 0) {
140 // Negate.
141 code = ArmConditionEncoding(NegateComparison(mir->meta.ccode));
142 }
143 LoadConstantNoClobber(rl_result.reg, true_val == 0 ? false_val : true_val);
144 left_op = zero_reg;
145 right_op = rl_result.reg.GetReg();
146 opcode = is_wide ? WIDE(kA64Csel4rrrc) : kA64Csel4rrrc;
147 } else if (true_val == 1 || false_val == 1) {
148 // CSInc half cheap based on wzr.
149 rl_result = EvalLoc(rl_dest, result_reg_class, true);
150 rl_result_evaled = true;
151 if (true_val == 1) {
152 // Negate.
153 code = ArmConditionEncoding(NegateComparison(mir->meta.ccode));
154 }
155 LoadConstantNoClobber(rl_result.reg, true_val == 1 ? false_val : true_val);
156 left_op = rl_result.reg.GetReg();
157 right_op = zero_reg;
158 opcode = is_wide ? WIDE(kA64Csinc4rrrc) : kA64Csinc4rrrc;
159 } else if (true_val == 0xFFFFFFFF || false_val == 0xFFFFFFFF) {
160 // CSneg half cheap based on wzr.
161 rl_result = EvalLoc(rl_dest, result_reg_class, true);
162 rl_result_evaled = true;
163 if (true_val == 0xFFFFFFFF) {
164 // Negate.
165 code = ArmConditionEncoding(NegateComparison(mir->meta.ccode));
166 }
167 LoadConstantNoClobber(rl_result.reg, true_val == 0xFFFFFFFF ? false_val : true_val);
168 left_op = rl_result.reg.GetReg();
169 right_op = zero_reg;
170 opcode = is_wide ? WIDE(kA64Csneg4rrrc) : kA64Csneg4rrrc;
171 } else {
172 // Csel. The rest. Use rl_result and a temp.
173 // TODO: To minimize the constants being loaded, check whether one can be inexpensively
174 // loaded as n - 1 or ~n.
175 rl_result = EvalLoc(rl_dest, result_reg_class, true);
176 rl_result_evaled = true;
177 LoadConstantNoClobber(rl_result.reg, true_val);
178 RegStorage t_reg2 = AllocTypedTemp(false, result_reg_class);
179 if (rl_dest.wide) {
180 if (t_reg2.Is32Bit()) {
181 t_reg2 = As64BitReg(t_reg2);
182 }
183 }
184 LoadConstantNoClobber(t_reg2, false_val);
185
186 // Use csel.
187 left_op = rl_result.reg.GetReg();
188 right_op = t_reg2.GetReg();
189 opcode = is_wide ? WIDE(kA64Csel4rrrc) : kA64Csel4rrrc;
190 }
191
192 if (!rl_result_evaled) {
193 rl_result = EvalLoc(rl_dest, result_reg_class, true);
194 }
195
196 NewLIR4(opcode, rl_result.reg.GetReg(), left_op, right_op, code);
197 } else {
198 RegLocation rl_true = mir_graph_->reg_location_[mir->ssa_rep->uses[1]];
199 RegLocation rl_false = mir_graph_->reg_location_[mir->ssa_rep->uses[2]];
200
201 rl_true = LoadValue(rl_true, result_reg_class);
202 rl_false = LoadValue(rl_false, result_reg_class);
203 rl_result = EvalLoc(rl_dest, result_reg_class, true);
204
205 int opcode = is_wide ? WIDE(kA64Csel4rrrc) : kA64Csel4rrrc;
206 NewLIR4(opcode, rl_result.reg.GetReg(),
207 rl_true.reg.GetReg(), rl_false.reg.GetReg(), code);
208 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100209 StoreValue(rl_dest, rl_result);
210}
211
212void Arm64Mir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
213 RegLocation rl_src1 = mir_graph_->GetSrcWide(mir, 0);
214 RegLocation rl_src2 = mir_graph_->GetSrcWide(mir, 2);
Serban Constantinescu05e27ff2014-05-28 13:21:45 +0100215 LIR* taken = &block_label_list_[bb->taken];
216 LIR* not_taken = &block_label_list_[bb->fall_through];
Matteo Franchin43ec8732014-03-31 15:00:14 +0100217 // Normalize such that if either operand is constant, src2 will be constant.
218 ConditionCode ccode = mir->meta.ccode;
219 if (rl_src1.is_const) {
220 std::swap(rl_src1, rl_src2);
221 ccode = FlipComparisonOrder(ccode);
222 }
Serban Constantinescu05e27ff2014-05-28 13:21:45 +0100223
Andreas Gampe381f8ac2014-07-10 03:23:41 -0700224 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
225
Matteo Franchin43ec8732014-03-31 15:00:14 +0100226 if (rl_src2.is_const) {
Andreas Gampe381f8ac2014-07-10 03:23:41 -0700227 // TODO: Optimize for rl_src1.is_const? (Does happen in the boot image at the moment.)
228
Matteo Franchin43ec8732014-03-31 15:00:14 +0100229 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
Serban Constantinescu05e27ff2014-05-28 13:21:45 +0100230 // Special handling using cbz & cbnz.
231 if (val == 0 && (ccode == kCondEq || ccode == kCondNe)) {
232 OpCmpImmBranch(ccode, rl_src1.reg, 0, taken);
233 OpCmpImmBranch(NegateComparison(ccode), rl_src1.reg, 0, not_taken);
234 return;
Andreas Gampe381f8ac2014-07-10 03:23:41 -0700235 }
236
Serban Constantinescu05e27ff2014-05-28 13:21:45 +0100237 // Only handle Imm if src2 is not already in a register.
Andreas Gampe381f8ac2014-07-10 03:23:41 -0700238 rl_src2 = UpdateLocWide(rl_src2);
239 if (rl_src2.location != kLocPhysReg) {
Serban Constantinescu05e27ff2014-05-28 13:21:45 +0100240 OpRegImm64(kOpCmp, rl_src1.reg, val);
241 OpCondBranch(ccode, taken);
242 OpCondBranch(NegateComparison(ccode), not_taken);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100243 return;
244 }
245 }
Serban Constantinescu05e27ff2014-05-28 13:21:45 +0100246
Matteo Franchin43ec8732014-03-31 15:00:14 +0100247 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
Serban Constantinescu05e27ff2014-05-28 13:21:45 +0100248 OpRegReg(kOpCmp, rl_src1.reg, rl_src2.reg);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100249 OpCondBranch(ccode, taken);
Serban Constantinescu05e27ff2014-05-28 13:21:45 +0100250 OpCondBranch(NegateComparison(ccode), not_taken);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100251}
252
253/*
254 * Generate a register comparison to an immediate and branch. Caller
255 * is responsible for setting branch target field.
256 */
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100257LIR* Arm64Mir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value,
258 LIR* target) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100259 LIR* branch;
260 ArmConditionCode arm_cond = ArmConditionEncoding(cond);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100261 if (check_value == 0 && (arm_cond == kArmCondEq || arm_cond == kArmCondNe)) {
262 ArmOpcode opcode = (arm_cond == kArmCondEq) ? kA64Cbz2rt : kA64Cbnz2rt;
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100263 ArmOpcode wide = reg.Is64Bit() ? WIDE(0) : UNWIDE(0);
264 branch = NewLIR2(opcode | wide, reg.GetReg(), 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100265 } else {
266 OpRegImm(kOpCmp, reg, check_value);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100267 branch = NewLIR2(kA64B2ct, arm_cond, 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100268 }
269 branch->target = target;
270 return branch;
271}
272
Zheng Xu7c1c2632014-06-17 18:17:31 +0800273LIR* Arm64Mir2Lir::OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg,
274 RegStorage base_reg, int offset, int check_value,
Nicolas Geoffray0025a862014-07-11 08:26:40 +0000275 LIR* target) {
Zheng Xu7c1c2632014-06-17 18:17:31 +0800276 // It is possible that temp register is 64-bit. (ArgReg or RefReg)
277 // Always compare 32-bit value no matter what temp_reg is.
278 if (temp_reg.Is64Bit()) {
279 temp_reg = As32BitReg(temp_reg);
280 }
281 Load32Disp(base_reg, offset, temp_reg);
282 LIR* branch = OpCmpImmBranch(cond, temp_reg, check_value, target);
283 return branch;
284}
285
Matteo Franchin43ec8732014-03-31 15:00:14 +0100286LIR* Arm64Mir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100287 bool dest_is_fp = r_dest.IsFloat();
288 bool src_is_fp = r_src.IsFloat();
289 ArmOpcode opcode = kA64Brk1d;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100290 LIR* res;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100291
292 if (LIKELY(dest_is_fp == src_is_fp)) {
293 if (LIKELY(!dest_is_fp)) {
Andreas Gampe4b537a82014-06-30 22:24:53 -0700294 DCHECK_EQ(r_dest.Is64Bit(), r_src.Is64Bit());
295
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100296 // Core/core copy.
297 // Copies involving the sp register require a different instruction.
298 opcode = UNLIKELY(A64_REG_IS_SP(r_dest.GetReg())) ? kA64Add4RRdT : kA64Mov2rr;
299
300 // TODO(Arm64): kA64Add4RRdT formally has 4 args, but is used as a 2 args instruction.
301 // This currently works because the other arguments are set to 0 by default. We should
302 // rather introduce an alias kA64Mov2RR.
303
304 // core/core copy. Do a x/x copy only if both registers are x.
305 if (r_dest.Is64Bit() && r_src.Is64Bit()) {
306 opcode = WIDE(opcode);
307 }
308 } else {
309 // Float/float copy.
310 bool dest_is_double = r_dest.IsDouble();
311 bool src_is_double = r_src.IsDouble();
312
313 // We do not do float/double or double/float casts here.
314 DCHECK_EQ(dest_is_double, src_is_double);
315
316 // Homogeneous float/float copy.
317 opcode = (dest_is_double) ? FWIDE(kA64Fmov2ff) : kA64Fmov2ff;
318 }
319 } else {
320 // Inhomogeneous register copy.
321 if (dest_is_fp) {
322 if (r_dest.IsDouble()) {
323 opcode = kA64Fmov2Sx;
324 } else {
Andreas Gampe4b537a82014-06-30 22:24:53 -0700325 r_src = Check32BitReg(r_src);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100326 opcode = kA64Fmov2sw;
327 }
328 } else {
329 if (r_src.IsDouble()) {
330 opcode = kA64Fmov2xS;
331 } else {
Andreas Gampe4b537a82014-06-30 22:24:53 -0700332 r_dest = Check32BitReg(r_dest);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100333 opcode = kA64Fmov2ws;
334 }
335 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100336 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100337
Matteo Franchin43ec8732014-03-31 15:00:14 +0100338 res = RawLIR(current_dalvik_offset_, opcode, r_dest.GetReg(), r_src.GetReg());
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100339
Matteo Franchin43ec8732014-03-31 15:00:14 +0100340 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
341 res->flags.is_nop = true;
342 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100343
Matteo Franchin43ec8732014-03-31 15:00:14 +0100344 return res;
345}
346
347void Arm64Mir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
348 if (r_dest != r_src) {
349 LIR* res = OpRegCopyNoInsert(r_dest, r_src);
350 AppendLIR(res);
351 }
352}
353
354void Arm64Mir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100355 OpRegCopy(r_dest, r_src);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100356}
357
358// Table of magic divisors
359struct MagicTable {
360 uint32_t magic;
361 uint32_t shift;
362 DividePattern pattern;
363};
364
365static const MagicTable magic_table[] = {
366 {0, 0, DivideNone}, // 0
367 {0, 0, DivideNone}, // 1
368 {0, 0, DivideNone}, // 2
369 {0x55555556, 0, Divide3}, // 3
370 {0, 0, DivideNone}, // 4
371 {0x66666667, 1, Divide5}, // 5
372 {0x2AAAAAAB, 0, Divide3}, // 6
373 {0x92492493, 2, Divide7}, // 7
374 {0, 0, DivideNone}, // 8
375 {0x38E38E39, 1, Divide5}, // 9
376 {0x66666667, 2, Divide5}, // 10
377 {0x2E8BA2E9, 1, Divide5}, // 11
378 {0x2AAAAAAB, 1, Divide5}, // 12
379 {0x4EC4EC4F, 2, Divide5}, // 13
380 {0x92492493, 3, Divide7}, // 14
381 {0x88888889, 3, Divide7}, // 15
382};
383
384// Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
385bool Arm64Mir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
Matteo Franchinc61b3c92014-06-18 11:52:47 +0100386 RegLocation rl_src, RegLocation rl_dest, int lit) {
387 if ((lit < 0) || (lit >= static_cast<int>(arraysize(magic_table)))) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100388 return false;
389 }
390 DividePattern pattern = magic_table[lit].pattern;
391 if (pattern == DivideNone) {
392 return false;
393 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100394 // Tuning: add rem patterns
395 if (!is_div) {
396 return false;
397 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100398
399 RegStorage r_magic = AllocTemp();
400 LoadConstant(r_magic, magic_table[lit].magic);
401 rl_src = LoadValue(rl_src, kCoreReg);
402 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Matteo Franchinc61b3c92014-06-18 11:52:47 +0100403 RegStorage r_long_mul = AllocTemp();
404 NewLIR4(kA64Smaddl4xwwx, As64BitReg(r_long_mul).GetReg(),
405 r_magic.GetReg(), rl_src.reg.GetReg(), rxzr);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100406 switch (pattern) {
407 case Divide3:
Matteo Franchinc61b3c92014-06-18 11:52:47 +0100408 OpRegRegImm(kOpLsr, As64BitReg(r_long_mul), As64BitReg(r_long_mul), 32);
409 OpRegRegRegShift(kOpSub, rl_result.reg, r_long_mul, rl_src.reg, EncodeShift(kA64Asr, 31));
Matteo Franchin43ec8732014-03-31 15:00:14 +0100410 break;
411 case Divide5:
Matteo Franchinc61b3c92014-06-18 11:52:47 +0100412 OpRegRegImm(kOpAsr, As64BitReg(r_long_mul), As64BitReg(r_long_mul),
413 32 + magic_table[lit].shift);
414 OpRegRegRegShift(kOpSub, rl_result.reg, r_long_mul, rl_src.reg, EncodeShift(kA64Asr, 31));
Matteo Franchin43ec8732014-03-31 15:00:14 +0100415 break;
416 case Divide7:
Matteo Franchinc61b3c92014-06-18 11:52:47 +0100417 OpRegRegRegShift(kOpAdd, As64BitReg(r_long_mul), As64BitReg(rl_src.reg),
418 As64BitReg(r_long_mul), EncodeShift(kA64Lsr, 32));
419 OpRegRegImm(kOpAsr, r_long_mul, r_long_mul, magic_table[lit].shift);
420 OpRegRegRegShift(kOpSub, rl_result.reg, r_long_mul, rl_src.reg, EncodeShift(kA64Asr, 31));
Matteo Franchin43ec8732014-03-31 15:00:14 +0100421 break;
422 default:
423 LOG(FATAL) << "Unexpected pattern: " << pattern;
424 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100425 StoreValue(rl_dest, rl_result);
426 return true;
427}
428
Matteo Franchinc61b3c92014-06-18 11:52:47 +0100429// Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit'
430// and store the result in 'rl_dest'.
431bool Arm64Mir2Lir::HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div,
432 RegLocation rl_src, RegLocation rl_dest, int lit) {
433 if (lit < 2) {
434 return false;
435 }
436 if (!IsPowerOfTwo(lit)) {
437 return SmallLiteralDivRem(dalvik_opcode, is_div, rl_src, rl_dest, lit);
438 }
439 int k = LowestSetBit(lit);
440 if (k >= 30) {
441 // Avoid special cases.
442 return false;
443 }
444 rl_src = LoadValue(rl_src, kCoreReg);
445 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
446 if (is_div) {
447 RegStorage t_reg = AllocTemp();
448 if (lit == 2) {
449 // Division by 2 is by far the most common division by constant.
450 OpRegRegRegShift(kOpAdd, t_reg, rl_src.reg, rl_src.reg, EncodeShift(kA64Lsr, 32 - k));
451 OpRegRegImm(kOpAsr, rl_result.reg, t_reg, k);
452 } else {
453 OpRegRegImm(kOpAsr, t_reg, rl_src.reg, 31);
454 OpRegRegRegShift(kOpAdd, t_reg, rl_src.reg, t_reg, EncodeShift(kA64Lsr, 32 - k));
455 OpRegRegImm(kOpAsr, rl_result.reg, t_reg, k);
456 }
457 } else {
458 RegStorage t_reg = AllocTemp();
459 if (lit == 2) {
460 OpRegRegRegShift(kOpAdd, t_reg, rl_src.reg, rl_src.reg, EncodeShift(kA64Lsr, 32 - k));
461 OpRegRegImm(kOpAnd, t_reg, t_reg, lit - 1);
462 OpRegRegRegShift(kOpSub, rl_result.reg, t_reg, rl_src.reg, EncodeShift(kA64Lsr, 32 - k));
463 } else {
464 RegStorage t_reg2 = AllocTemp();
465 OpRegRegImm(kOpAsr, t_reg, rl_src.reg, 31);
466 OpRegRegRegShift(kOpAdd, t_reg2, rl_src.reg, t_reg, EncodeShift(kA64Lsr, 32 - k));
467 OpRegRegImm(kOpAnd, t_reg2, t_reg2, lit - 1);
468 OpRegRegRegShift(kOpSub, rl_result.reg, t_reg2, t_reg, EncodeShift(kA64Lsr, 32 - k));
469 }
470 }
471 StoreValue(rl_dest, rl_result);
472 return true;
473}
474
Matteo Franchin43ec8732014-03-31 15:00:14 +0100475bool Arm64Mir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100476 LOG(FATAL) << "Unexpected use of EasyMultiply for Arm64";
477 return false;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100478}
479
480RegLocation Arm64Mir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
Matteo Franchinc61b3c92014-06-18 11:52:47 +0100481 RegLocation rl_src2, bool is_div, bool check_zero) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100482 LOG(FATAL) << "Unexpected use of GenDivRem for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +0100483 return rl_dest;
484}
485
486RegLocation Arm64Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100487 LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +0100488 return rl_dest;
489}
490
491RegLocation Arm64Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit, bool is_div) {
492 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
493
494 // Put the literal in a temp.
495 RegStorage lit_temp = AllocTemp();
496 LoadConstant(lit_temp, lit);
497 // Use the generic case for div/rem with arg2 in a register.
498 // TODO: The literal temp can be freed earlier during a modulus to reduce reg pressure.
499 rl_result = GenDivRem(rl_result, reg1, lit_temp, is_div);
500 FreeTemp(lit_temp);
501
502 return rl_result;
503}
504
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100505RegLocation Arm64Mir2Lir::GenDivRem(RegLocation rl_dest, RegStorage r_src1, RegStorage r_src2,
Matteo Franchin43ec8732014-03-31 15:00:14 +0100506 bool is_div) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100507 CHECK_EQ(r_src1.Is64Bit(), r_src2.Is64Bit());
508
Matteo Franchin43ec8732014-03-31 15:00:14 +0100509 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
510 if (is_div) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100511 OpRegRegReg(kOpDiv, rl_result.reg, r_src1, r_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100512 } else {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100513 // temp = r_src1 / r_src2
514 // dest = r_src1 - temp * r_src2
515 RegStorage temp;
516 ArmOpcode wide;
517 if (rl_result.reg.Is64Bit()) {
518 temp = AllocTempWide();
519 wide = WIDE(0);
520 } else {
521 temp = AllocTemp();
522 wide = UNWIDE(0);
523 }
524 OpRegRegReg(kOpDiv, temp, r_src1, r_src2);
525 NewLIR4(kA64Msub4rrrr | wide, rl_result.reg.GetReg(), temp.GetReg(),
526 r_src1.GetReg(), r_src2.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100527 FreeTemp(temp);
528 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100529 return rl_result;
530}
531
Serban Constantinescu169489b2014-06-11 16:43:35 +0100532bool Arm64Mir2Lir::GenInlinedAbsLong(CallInfo* info) {
533 RegLocation rl_src = info->args[0];
534 rl_src = LoadValueWide(rl_src, kCoreReg);
535 RegLocation rl_dest = InlineTargetWide(info);
536 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
537 RegStorage sign_reg = AllocTempWide();
538 // abs(x) = y<=x>>63, (x+y)^y.
539 OpRegRegImm(kOpAsr, sign_reg, rl_src.reg, 63);
540 OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, sign_reg);
541 OpRegReg(kOpXor, rl_result.reg, sign_reg);
542 StoreValueWide(rl_dest, rl_result);
543 return true;
544}
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100545
Serban Constantinescu23abec92014-07-02 16:13:38 +0100546bool Arm64Mir2Lir::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) {
Serban Constantinescu169489b2014-06-11 16:43:35 +0100547 DCHECK_EQ(cu_->instruction_set, kArm64);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100548 RegLocation rl_src1 = info->args[0];
Serban Constantinescu23abec92014-07-02 16:13:38 +0100549 RegLocation rl_src2 = (is_long) ? info->args[2] : info->args[1];
550 rl_src1 = (is_long) ? LoadValueWide(rl_src1, kCoreReg) : LoadValue(rl_src1, kCoreReg);
551 rl_src2 = (is_long) ? LoadValueWide(rl_src2, kCoreReg) : LoadValue(rl_src2, kCoreReg);
552 RegLocation rl_dest = (is_long) ? InlineTargetWide(info) : InlineTarget(info);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100553 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
554 OpRegReg(kOpCmp, rl_src1.reg, rl_src2.reg);
Serban Constantinescu23abec92014-07-02 16:13:38 +0100555 NewLIR4((is_long) ? WIDE(kA64Csel4rrrc) : kA64Csel4rrrc, rl_result.reg.GetReg(),
556 rl_src1.reg.GetReg(), rl_src2.reg.GetReg(), (is_min) ? kArmCondLt : kArmCondGt);
557 (is_long) ? StoreValueWide(rl_dest, rl_result) :StoreValue(rl_dest, rl_result);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100558 return true;
559}
560
561bool Arm64Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
562 RegLocation rl_src_address = info->args[0]; // long address
Serban Constantinescu63fe93d2014-06-30 17:10:28 +0100563 RegLocation rl_dest = (size == k64) ? InlineTargetWide(info) : InlineTarget(info);
564 RegLocation rl_address = LoadValueWide(rl_src_address, kCoreReg);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100565 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Serban Constantinescu169489b2014-06-11 16:43:35 +0100566
Andreas Gampe3c12c512014-06-24 18:46:29 +0000567 LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100568 if (size == k64) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100569 StoreValueWide(rl_dest, rl_result);
570 } else {
571 DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100572 StoreValue(rl_dest, rl_result);
573 }
574 return true;
575}
576
577bool Arm64Mir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
578 RegLocation rl_src_address = info->args[0]; // long address
Matteo Franchin43ec8732014-03-31 15:00:14 +0100579 RegLocation rl_src_value = info->args[2]; // [size] value
Serban Constantinescu63fe93d2014-06-30 17:10:28 +0100580 RegLocation rl_address = LoadValueWide(rl_src_address, kCoreReg);
Serban Constantinescu169489b2014-06-11 16:43:35 +0100581
582 RegLocation rl_value;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100583 if (size == k64) {
Serban Constantinescu169489b2014-06-11 16:43:35 +0100584 rl_value = LoadValueWide(rl_src_value, kCoreReg);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100585 } else {
586 DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
Serban Constantinescu169489b2014-06-11 16:43:35 +0100587 rl_value = LoadValue(rl_src_value, kCoreReg);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100588 }
Andreas Gampe3c12c512014-06-24 18:46:29 +0000589 StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100590 return true;
591}
592
593void Arm64Mir2Lir::OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale, int offset) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100594 LOG(FATAL) << "Unexpected use of OpLea for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +0100595}
596
Andreas Gampe2f244e92014-05-08 03:35:25 -0700597void Arm64Mir2Lir::OpTlsCmp(ThreadOffset<4> offset, int val) {
598 UNIMPLEMENTED(FATAL) << "Should not be used.";
599}
600
601void Arm64Mir2Lir::OpTlsCmp(ThreadOffset<8> offset, int val) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100602 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +0100603}
604
605bool Arm64Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
Serban Constantinescu169489b2014-06-11 16:43:35 +0100606 DCHECK_EQ(cu_->instruction_set, kArm64);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100607 // Unused - RegLocation rl_src_unsafe = info->args[0];
608 RegLocation rl_src_obj = info->args[1]; // Object - known non-null
609 RegLocation rl_src_offset = info->args[2]; // long low
Matteo Franchin43ec8732014-03-31 15:00:14 +0100610 RegLocation rl_src_expected = info->args[4]; // int, long or Object
611 // If is_long, high half is in info->args[5]
612 RegLocation rl_src_new_value = info->args[is_long ? 6 : 5]; // int, long or Object
613 // If is_long, high half is in info->args[7]
614 RegLocation rl_dest = InlineTarget(info); // boolean place for result
615
Serban Constantinescu169489b2014-06-11 16:43:35 +0100616 // Load Object and offset
buzbeea0cd2d72014-06-01 09:33:49 -0700617 RegLocation rl_object = LoadValue(rl_src_obj, kRefReg);
Serban Constantinescu63fe93d2014-06-30 17:10:28 +0100618 RegLocation rl_offset = LoadValueWide(rl_src_offset, kCoreReg);
Serban Constantinescu169489b2014-06-11 16:43:35 +0100619
Matteo Franchin43ec8732014-03-31 15:00:14 +0100620 RegLocation rl_new_value;
Serban Constantinescu169489b2014-06-11 16:43:35 +0100621 RegLocation rl_expected;
622 if (is_long) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100623 rl_new_value = LoadValueWide(rl_src_new_value, kCoreReg);
Serban Constantinescu169489b2014-06-11 16:43:35 +0100624 rl_expected = LoadValueWide(rl_src_expected, kCoreReg);
625 } else {
626 rl_new_value = LoadValue(rl_src_new_value, is_object ? kRefReg : kCoreReg);
627 rl_expected = LoadValue(rl_src_expected, is_object ? kRefReg : kCoreReg);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100628 }
629
630 if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
631 // Mark card for object assuming new value is stored.
632 MarkGCCard(rl_new_value.reg, rl_object.reg);
633 }
634
Serban Constantinescu169489b2014-06-11 16:43:35 +0100635 RegStorage r_ptr = AllocTempRef();
Matteo Franchin43ec8732014-03-31 15:00:14 +0100636 OpRegRegReg(kOpAdd, r_ptr, rl_object.reg, rl_offset.reg);
637
638 // Free now unneeded rl_object and rl_offset to give more temps.
639 ClobberSReg(rl_object.s_reg_low);
640 FreeTemp(rl_object.reg);
641 ClobberSReg(rl_offset.s_reg_low);
642 FreeTemp(rl_offset.reg);
643
Matteo Franchin43ec8732014-03-31 15:00:14 +0100644 // do {
645 // tmp = [r_ptr] - expected;
646 // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
647 // result = tmp != 0;
648
Serban Constantinescu169489b2014-06-11 16:43:35 +0100649 RegStorage r_tmp;
Serban Constantinescu63fe93d2014-06-30 17:10:28 +0100650 RegStorage r_tmp_stored;
651 RegStorage rl_new_value_stored = rl_new_value.reg;
652 ArmOpcode wide = UNWIDE(0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100653 if (is_long) {
Serban Constantinescu63fe93d2014-06-30 17:10:28 +0100654 r_tmp_stored = r_tmp = AllocTempWide();
655 wide = WIDE(0);
Serban Constantinescu169489b2014-06-11 16:43:35 +0100656 } else if (is_object) {
Serban Constantinescu63fe93d2014-06-30 17:10:28 +0100657 // References use 64-bit registers, but are stored as compressed 32-bit values.
658 // This means r_tmp_stored != r_tmp.
Serban Constantinescu169489b2014-06-11 16:43:35 +0100659 r_tmp = AllocTempRef();
Serban Constantinescu63fe93d2014-06-30 17:10:28 +0100660 r_tmp_stored = As32BitReg(r_tmp);
661 rl_new_value_stored = As32BitReg(rl_new_value_stored);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100662 } else {
Serban Constantinescu63fe93d2014-06-30 17:10:28 +0100663 r_tmp_stored = r_tmp = AllocTemp();
Matteo Franchin43ec8732014-03-31 15:00:14 +0100664 }
665
Serban Constantinescu63fe93d2014-06-30 17:10:28 +0100666 RegStorage r_tmp32 = (r_tmp.Is32Bit()) ? r_tmp : As32BitReg(r_tmp);
Serban Constantinescu169489b2014-06-11 16:43:35 +0100667 LIR* loop = NewLIR0(kPseudoTargetLabel);
Serban Constantinescu63fe93d2014-06-30 17:10:28 +0100668 NewLIR2(kA64Ldaxr2rX | wide, r_tmp_stored.GetReg(), r_ptr.GetReg());
Serban Constantinescu169489b2014-06-11 16:43:35 +0100669 OpRegReg(kOpCmp, r_tmp, rl_expected.reg);
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100670 DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode));
Serban Constantinescu169489b2014-06-11 16:43:35 +0100671 LIR* early_exit = OpCondBranch(kCondNe, NULL);
Serban Constantinescu63fe93d2014-06-30 17:10:28 +0100672 NewLIR3(kA64Stlxr3wrX | wide, r_tmp32.GetReg(), rl_new_value_stored.GetReg(), r_ptr.GetReg());
673 NewLIR3(kA64Cmp3RdT, r_tmp32.GetReg(), 0, ENCODE_NO_SHIFT);
Serban Constantinescu169489b2014-06-11 16:43:35 +0100674 DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode));
675 OpCondBranch(kCondNe, loop);
676
Serban Constantinescu63fe93d2014-06-30 17:10:28 +0100677 LIR* exit_loop = NewLIR0(kPseudoTargetLabel);
678 early_exit->target = exit_loop;
679
Serban Constantinescu169489b2014-06-11 16:43:35 +0100680 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Serban Constantinescu63fe93d2014-06-30 17:10:28 +0100681 NewLIR4(kA64Csinc4rrrc, rl_result.reg.GetReg(), rwzr, rwzr, kArmCondNe);
Serban Constantinescu169489b2014-06-11 16:43:35 +0100682
Matteo Franchin43ec8732014-03-31 15:00:14 +0100683 FreeTemp(r_tmp); // Now unneeded.
Serban Constantinescu169489b2014-06-11 16:43:35 +0100684 FreeTemp(r_ptr); // Now unneeded.
Matteo Franchin43ec8732014-03-31 15:00:14 +0100685
686 StoreValue(rl_dest, rl_result);
687
Matteo Franchin43ec8732014-03-31 15:00:14 +0100688 return true;
689}
690
691LIR* Arm64Mir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100692 return RawLIR(current_dalvik_offset_, WIDE(kA64Ldr2rp), reg.GetReg(), 0, 0, 0, 0, target);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100693}
694
695LIR* Arm64Mir2Lir::OpVldm(RegStorage r_base, int count) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100696 LOG(FATAL) << "Unexpected use of OpVldm for Arm64";
697 return NULL;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100698}
699
700LIR* Arm64Mir2Lir::OpVstm(RegStorage r_base, int count) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100701 LOG(FATAL) << "Unexpected use of OpVstm for Arm64";
702 return NULL;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100703}
704
705void Arm64Mir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
706 RegLocation rl_result, int lit,
707 int first_bit, int second_bit) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100708 OpRegRegRegShift(kOpAdd, rl_result.reg, rl_src.reg, rl_src.reg, EncodeShift(kA64Lsl, second_bit - first_bit));
Matteo Franchin43ec8732014-03-31 15:00:14 +0100709 if (first_bit != 0) {
710 OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit);
711 }
712}
713
714void Arm64Mir2Lir::GenDivZeroCheckWide(RegStorage reg) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100715 LOG(FATAL) << "Unexpected use of GenDivZero for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +0100716}
717
718// Test suspend flag, return target of taken suspend branch
719LIR* Arm64Mir2Lir::OpTestSuspend(LIR* target) {
Zheng Xubaa7c882014-06-30 14:26:50 +0800720 NewLIR3(kA64Subs3rRd, rwSUSPEND, rwSUSPEND, 1);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100721 return OpCondBranch((target == NULL) ? kCondEq : kCondNe, target);
722}
723
724// Decrement register and branch on condition
725LIR* Arm64Mir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) {
buzbee33ae5582014-06-12 14:56:32 -0700726 // Combine sub & test using sub setflags encoding here. We need to make sure a
727 // subtract form that sets carry is used, so generate explicitly.
728 // TODO: might be best to add a new op, kOpSubs, and handle it generically.
729 ArmOpcode opcode = reg.Is64Bit() ? WIDE(kA64Subs3rRd) : UNWIDE(kA64Subs3rRd);
730 NewLIR3(opcode, reg.GetReg(), reg.GetReg(), 1); // For value == 1, this should set flags.
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100731 DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode));
Matteo Franchin43ec8732014-03-31 15:00:14 +0100732 return OpCondBranch(c_code, target);
733}
734
Andreas Gampeb14329f2014-05-15 11:16:06 -0700735bool Arm64Mir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100736#if ANDROID_SMP != 0
737 // Start off with using the last LIR as the barrier. If it is not enough, then we will generate one.
738 LIR* barrier = last_lir_insn_;
739
740 int dmb_flavor;
741 // TODO: revisit Arm barrier kinds
742 switch (barrier_kind) {
743 case kLoadStore: dmb_flavor = kISH; break;
744 case kLoadLoad: dmb_flavor = kISH; break;
745 case kStoreStore: dmb_flavor = kISHST; break;
746 case kStoreLoad: dmb_flavor = kISH; break;
747 default:
748 LOG(FATAL) << "Unexpected MemBarrierKind: " << barrier_kind;
749 dmb_flavor = kSY; // quiet gcc.
750 break;
751 }
752
Andreas Gampeb14329f2014-05-15 11:16:06 -0700753 bool ret = false;
754
Matteo Franchin43ec8732014-03-31 15:00:14 +0100755 // If the same barrier already exists, don't generate another.
756 if (barrier == nullptr
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100757 || (barrier->opcode != kA64Dmb1B || barrier->operands[0] != dmb_flavor)) {
758 barrier = NewLIR1(kA64Dmb1B, dmb_flavor);
Andreas Gampeb14329f2014-05-15 11:16:06 -0700759 ret = true;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100760 }
761
762 // At this point we must have a memory barrier. Mark it as a scheduling barrier as well.
763 DCHECK(!barrier->flags.use_def_invalid);
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100764 barrier->u.m.def_mask = &kEncodeAll;
Andreas Gampeb14329f2014-05-15 11:16:06 -0700765 return ret;
766#else
767 return false;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100768#endif
769}
770
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100771void Arm64Mir2Lir::GenIntToLong(RegLocation rl_dest, RegLocation rl_src) {
772 RegLocation rl_result;
773
774 rl_src = LoadValue(rl_src, kCoreReg);
775 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Andreas Gampe4b537a82014-06-30 22:24:53 -0700776 NewLIR4(WIDE(kA64Sbfm4rrdd), rl_result.reg.GetReg(), As64BitReg(rl_src.reg).GetReg(), 0, 31);
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100777 StoreValueWide(rl_dest, rl_result);
778}
779
780void Arm64Mir2Lir::GenDivRemLong(Instruction::Code opcode, RegLocation rl_dest,
781 RegLocation rl_src1, RegLocation rl_src2, bool is_div) {
782 RegLocation rl_result;
783 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
784 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
785 GenDivZeroCheck(rl_src2.reg);
786 rl_result = GenDivRem(rl_dest, rl_src1.reg, rl_src2.reg, is_div);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100787 StoreValueWide(rl_dest, rl_result);
788}
789
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100790void Arm64Mir2Lir::GenLongOp(OpKind op, RegLocation rl_dest, RegLocation rl_src1,
791 RegLocation rl_src2) {
792 RegLocation rl_result;
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100793
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100794 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
795 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
796 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100797 OpRegRegRegShift(op, rl_result.reg, rl_src1.reg, rl_src2.reg, ENCODE_NO_SHIFT);
798 StoreValueWide(rl_dest, rl_result);
799}
800
801void Arm64Mir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
802 RegLocation rl_result;
803
804 rl_src = LoadValueWide(rl_src, kCoreReg);
805 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
806 OpRegRegShift(kOpNeg, rl_result.reg, rl_src.reg, ENCODE_NO_SHIFT);
807 StoreValueWide(rl_dest, rl_result);
808}
809
810void Arm64Mir2Lir::GenNotLong(RegLocation rl_dest, RegLocation rl_src) {
811 RegLocation rl_result;
812
813 rl_src = LoadValueWide(rl_src, kCoreReg);
814 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
815 OpRegRegShift(kOpMvn, rl_result.reg, rl_src.reg, ENCODE_NO_SHIFT);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100816 StoreValueWide(rl_dest, rl_result);
817}
818
Matteo Franchin43ec8732014-03-31 15:00:14 +0100819void Arm64Mir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest,
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100820 RegLocation rl_src1, RegLocation rl_src2) {
821 GenLongOp(kOpMul, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100822}
823
824void Arm64Mir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100825 RegLocation rl_src2) {
826 GenLongOp(kOpAdd, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100827}
828
829void Arm64Mir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
830 RegLocation rl_src2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100831 GenLongOp(kOpSub, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100832}
833
834void Arm64Mir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
835 RegLocation rl_src2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100836 GenLongOp(kOpAnd, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100837}
838
839void Arm64Mir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
840 RegLocation rl_src2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100841 GenLongOp(kOpOr, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100842}
843
844void Arm64Mir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
845 RegLocation rl_src2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100846 GenLongOp(kOpXor, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100847}
848
849/*
850 * Generate array load
851 */
852void Arm64Mir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
853 RegLocation rl_index, RegLocation rl_dest, int scale) {
854 RegisterClass reg_class = RegClassBySize(size);
855 int len_offset = mirror::Array::LengthOffset().Int32Value();
856 int data_offset;
857 RegLocation rl_result;
858 bool constant_index = rl_index.is_const;
buzbeea0cd2d72014-06-01 09:33:49 -0700859 rl_array = LoadValue(rl_array, kRefReg);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100860 if (!constant_index) {
861 rl_index = LoadValue(rl_index, kCoreReg);
862 }
863
864 if (rl_dest.wide) {
865 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
866 } else {
867 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
868 }
869
870 // If index is constant, just fold it into the data offset
871 if (constant_index) {
872 data_offset += mir_graph_->ConstantValue(rl_index) << scale;
873 }
874
875 /* null object? */
876 GenNullCheck(rl_array.reg, opt_flags);
877
878 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
879 RegStorage reg_len;
880 if (needs_range_check) {
881 reg_len = AllocTemp();
882 /* Get len */
883 Load32Disp(rl_array.reg, len_offset, reg_len);
884 MarkPossibleNullPointerException(opt_flags);
885 } else {
886 ForceImplicitNullCheck(rl_array.reg, opt_flags);
887 }
888 if (rl_dest.wide || rl_dest.fp || constant_index) {
889 RegStorage reg_ptr;
890 if (constant_index) {
891 reg_ptr = rl_array.reg; // NOTE: must not alter reg_ptr in constant case.
892 } else {
893 // No special indexed operation, lea + load w/ displacement
buzbeea0cd2d72014-06-01 09:33:49 -0700894 reg_ptr = AllocTempRef();
buzbee33ae5582014-06-12 14:56:32 -0700895 OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.reg, As64BitReg(rl_index.reg),
896 EncodeShift(kA64Lsl, scale));
Matteo Franchin43ec8732014-03-31 15:00:14 +0100897 FreeTemp(rl_index.reg);
898 }
899 rl_result = EvalLoc(rl_dest, reg_class, true);
900
901 if (needs_range_check) {
902 if (constant_index) {
903 GenArrayBoundsCheck(mir_graph_->ConstantValue(rl_index), reg_len);
904 } else {
905 GenArrayBoundsCheck(rl_index.reg, reg_len);
906 }
907 FreeTemp(reg_len);
908 }
Andreas Gampe3c12c512014-06-24 18:46:29 +0000909 if (rl_result.ref) {
910 LoadRefDisp(reg_ptr, data_offset, rl_result.reg, kNotVolatile);
911 } else {
912 LoadBaseDisp(reg_ptr, data_offset, rl_result.reg, size, kNotVolatile);
913 }
Vladimir Marko455759b2014-05-06 20:49:36 +0100914 MarkPossibleNullPointerException(opt_flags);
915 if (!constant_index) {
916 FreeTemp(reg_ptr);
917 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100918 if (rl_dest.wide) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100919 StoreValueWide(rl_dest, rl_result);
920 } else {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100921 StoreValue(rl_dest, rl_result);
922 }
923 } else {
924 // Offset base, then use indexed load
buzbeea0cd2d72014-06-01 09:33:49 -0700925 RegStorage reg_ptr = AllocTempRef();
Matteo Franchin43ec8732014-03-31 15:00:14 +0100926 OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
927 FreeTemp(rl_array.reg);
928 rl_result = EvalLoc(rl_dest, reg_class, true);
929
930 if (needs_range_check) {
931 GenArrayBoundsCheck(rl_index.reg, reg_len);
932 FreeTemp(reg_len);
933 }
Andreas Gampe3c12c512014-06-24 18:46:29 +0000934 if (rl_result.ref) {
Matteo Franchin255e0142014-07-04 13:50:41 +0100935 LoadRefIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_result.reg, scale);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000936 } else {
937 LoadBaseIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_result.reg, scale, size);
938 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100939 MarkPossibleNullPointerException(opt_flags);
940 FreeTemp(reg_ptr);
941 StoreValue(rl_dest, rl_result);
942 }
943}
944
945/*
946 * Generate array store
947 *
948 */
949void Arm64Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
950 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
951 RegisterClass reg_class = RegClassBySize(size);
952 int len_offset = mirror::Array::LengthOffset().Int32Value();
953 bool constant_index = rl_index.is_const;
954
955 int data_offset;
956 if (size == k64 || size == kDouble) {
957 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
958 } else {
959 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
960 }
961
962 // If index is constant, just fold it into the data offset.
963 if (constant_index) {
964 data_offset += mir_graph_->ConstantValue(rl_index) << scale;
965 }
966
buzbeea0cd2d72014-06-01 09:33:49 -0700967 rl_array = LoadValue(rl_array, kRefReg);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100968 if (!constant_index) {
969 rl_index = LoadValue(rl_index, kCoreReg);
970 }
971
972 RegStorage reg_ptr;
973 bool allocated_reg_ptr_temp = false;
974 if (constant_index) {
975 reg_ptr = rl_array.reg;
976 } else if (IsTemp(rl_array.reg) && !card_mark) {
977 Clobber(rl_array.reg);
978 reg_ptr = rl_array.reg;
979 } else {
980 allocated_reg_ptr_temp = true;
buzbeea0cd2d72014-06-01 09:33:49 -0700981 reg_ptr = AllocTempRef();
Matteo Franchin43ec8732014-03-31 15:00:14 +0100982 }
983
984 /* null object? */
985 GenNullCheck(rl_array.reg, opt_flags);
986
987 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
988 RegStorage reg_len;
989 if (needs_range_check) {
990 reg_len = AllocTemp();
991 // NOTE: max live temps(4) here.
992 /* Get len */
993 Load32Disp(rl_array.reg, len_offset, reg_len);
994 MarkPossibleNullPointerException(opt_flags);
995 } else {
996 ForceImplicitNullCheck(rl_array.reg, opt_flags);
997 }
998 /* at this point, reg_ptr points to array, 2 live temps */
999 if (rl_src.wide || rl_src.fp || constant_index) {
1000 if (rl_src.wide) {
1001 rl_src = LoadValueWide(rl_src, reg_class);
1002 } else {
1003 rl_src = LoadValue(rl_src, reg_class);
1004 }
1005 if (!constant_index) {
buzbee33ae5582014-06-12 14:56:32 -07001006 OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.reg, As64BitReg(rl_index.reg),
1007 EncodeShift(kA64Lsl, scale));
Matteo Franchin43ec8732014-03-31 15:00:14 +01001008 }
1009 if (needs_range_check) {
1010 if (constant_index) {
1011 GenArrayBoundsCheck(mir_graph_->ConstantValue(rl_index), reg_len);
1012 } else {
1013 GenArrayBoundsCheck(rl_index.reg, reg_len);
1014 }
1015 FreeTemp(reg_len);
1016 }
Andreas Gampe3c12c512014-06-24 18:46:29 +00001017 if (rl_src.ref) {
1018 StoreRefDisp(reg_ptr, data_offset, rl_src.reg, kNotVolatile);
1019 } else {
1020 StoreBaseDisp(reg_ptr, data_offset, rl_src.reg, size, kNotVolatile);
1021 }
Matteo Franchin43ec8732014-03-31 15:00:14 +01001022 MarkPossibleNullPointerException(opt_flags);
1023 } else {
1024 /* reg_ptr -> array data */
1025 OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
1026 rl_src = LoadValue(rl_src, reg_class);
1027 if (needs_range_check) {
1028 GenArrayBoundsCheck(rl_index.reg, reg_len);
1029 FreeTemp(reg_len);
1030 }
Andreas Gampe3c12c512014-06-24 18:46:29 +00001031 if (rl_src.ref) {
Matteo Franchin255e0142014-07-04 13:50:41 +01001032 StoreRefIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_src.reg, scale);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001033 } else {
1034 StoreBaseIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_src.reg, scale, size);
1035 }
Matteo Franchin43ec8732014-03-31 15:00:14 +01001036 MarkPossibleNullPointerException(opt_flags);
1037 }
1038 if (allocated_reg_ptr_temp) {
1039 FreeTemp(reg_ptr);
1040 }
1041 if (card_mark) {
1042 MarkGCCard(rl_src.reg, rl_array.reg);
1043 }
1044}
1045
Matteo Franchin43ec8732014-03-31 15:00:14 +01001046void Arm64Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode,
1047 RegLocation rl_dest, RegLocation rl_src, RegLocation rl_shift) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001048 OpKind op = kOpBkpt;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001049 // Per spec, we only care about low 6 bits of shift amount.
1050 int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f;
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001051 rl_src = LoadValueWide(rl_src, kCoreReg);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001052 if (shift_amount == 0) {
1053 StoreValueWide(rl_dest, rl_src);
1054 return;
1055 }
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001056
1057 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001058 switch (opcode) {
1059 case Instruction::SHL_LONG:
1060 case Instruction::SHL_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001061 op = kOpLsl;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001062 break;
1063 case Instruction::SHR_LONG:
1064 case Instruction::SHR_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001065 op = kOpAsr;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001066 break;
1067 case Instruction::USHR_LONG:
1068 case Instruction::USHR_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001069 op = kOpLsr;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001070 break;
1071 default:
1072 LOG(FATAL) << "Unexpected case";
1073 }
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001074 OpRegRegImm(op, rl_result.reg, rl_src.reg, shift_amount);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001075 StoreValueWide(rl_dest, rl_result);
1076}
1077
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001078void Arm64Mir2Lir::GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
1079 RegLocation rl_src1, RegLocation rl_src2) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001080 if ((opcode == Instruction::SUB_LONG) || (opcode == Instruction::SUB_LONG_2ADDR)) {
Matteo Franchin43ec8732014-03-31 15:00:14 +01001081 if (!rl_src2.is_const) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001082 return GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001083 }
1084 } else {
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001085 // Associativity.
Matteo Franchin43ec8732014-03-31 15:00:14 +01001086 if (!rl_src2.is_const) {
1087 DCHECK(rl_src1.is_const);
1088 std::swap(rl_src1, rl_src2);
1089 }
1090 }
Matteo Franchin43ec8732014-03-31 15:00:14 +01001091 DCHECK(rl_src2.is_const);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001092
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001093 OpKind op = kOpBkpt;
1094 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
1095
Matteo Franchin43ec8732014-03-31 15:00:14 +01001096 switch (opcode) {
1097 case Instruction::ADD_LONG:
1098 case Instruction::ADD_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001099 op = kOpAdd;
1100 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001101 case Instruction::SUB_LONG:
1102 case Instruction::SUB_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001103 op = kOpSub;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001104 break;
1105 case Instruction::AND_LONG:
1106 case Instruction::AND_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001107 op = kOpAnd;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001108 break;
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001109 case Instruction::OR_LONG:
1110 case Instruction::OR_LONG_2ADDR:
1111 op = kOpOr;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001112 break;
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001113 case Instruction::XOR_LONG:
1114 case Instruction::XOR_LONG_2ADDR:
1115 op = kOpXor;
1116 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001117 default:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001118 LOG(FATAL) << "Unexpected opcode";
Matteo Franchin43ec8732014-03-31 15:00:14 +01001119 }
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001120
1121 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
1122 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Zheng Xue2eb29e2014-06-12 10:22:33 +08001123 OpRegRegImm64(op, rl_result.reg, rl_src1.reg, val);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001124 StoreValueWide(rl_dest, rl_result);
1125}
1126
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001127/**
1128 * @brief Split a register list in pairs or registers.
1129 *
1130 * Given a list of registers in @p reg_mask, split the list in pairs. Use as follows:
1131 * @code
1132 * int reg1 = -1, reg2 = -1;
1133 * while (reg_mask) {
1134 * reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1135 * if (UNLIKELY(reg2 < 0)) {
1136 * // Single register in reg1.
1137 * } else {
1138 * // Pair in reg1, reg2.
1139 * }
1140 * }
1141 * @endcode
1142 */
1143uint32_t Arm64Mir2Lir::GenPairWise(uint32_t reg_mask, int* reg1, int* reg2) {
1144 // Find first register.
1145 int first_bit_set = __builtin_ctz(reg_mask) + 1;
1146 int reg = *reg1 + first_bit_set;
1147 reg_mask >>= first_bit_set;
1148
1149 if (LIKELY(reg_mask)) {
1150 // Save the first register, find the second and use the pair opcode.
1151 int second_bit_set = __builtin_ctz(reg_mask) + 1;
1152 *reg2 = reg;
1153 reg_mask >>= second_bit_set;
1154 *reg1 = reg + second_bit_set;
1155 return reg_mask;
1156 }
1157
1158 // Use the single opcode, as we just have one register.
1159 *reg1 = reg;
1160 *reg2 = -1;
1161 return reg_mask;
1162}
1163
1164void Arm64Mir2Lir::UnSpillCoreRegs(RegStorage base, int offset, uint32_t reg_mask) {
1165 int reg1 = -1, reg2 = -1;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001166 const int reg_log2_size = 3;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001167
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001168 for (offset = (offset >> reg_log2_size); reg_mask; offset += 2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001169 reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1170 if (UNLIKELY(reg2 < 0)) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001171 NewLIR3(WIDE(kA64Ldr3rXD), RegStorage::Solo64(reg1).GetReg(), base.GetReg(), offset);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001172 } else {
buzbeeb5860fb2014-06-21 15:31:01 -07001173 DCHECK_LE(offset, 63);
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001174 NewLIR4(WIDE(kA64Ldp4rrXD), RegStorage::Solo64(reg2).GetReg(),
1175 RegStorage::Solo64(reg1).GetReg(), base.GetReg(), offset);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001176 }
1177 }
1178}
1179
1180void Arm64Mir2Lir::SpillCoreRegs(RegStorage base, int offset, uint32_t reg_mask) {
1181 int reg1 = -1, reg2 = -1;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001182 const int reg_log2_size = 3;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001183
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001184 for (offset = (offset >> reg_log2_size); reg_mask; offset += 2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001185 reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1186 if (UNLIKELY(reg2 < 0)) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001187 NewLIR3(WIDE(kA64Str3rXD), RegStorage::Solo64(reg1).GetReg(), base.GetReg(), offset);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001188 } else {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001189 NewLIR4(WIDE(kA64Stp4rrXD), RegStorage::Solo64(reg2).GetReg(),
1190 RegStorage::Solo64(reg1).GetReg(), base.GetReg(), offset);
1191 }
1192 }
1193}
1194
1195void Arm64Mir2Lir::UnSpillFPRegs(RegStorage base, int offset, uint32_t reg_mask) {
1196 int reg1 = -1, reg2 = -1;
1197 const int reg_log2_size = 3;
1198
1199 for (offset = (offset >> reg_log2_size); reg_mask; offset += 2) {
1200 reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1201 if (UNLIKELY(reg2 < 0)) {
1202 NewLIR3(FWIDE(kA64Ldr3fXD), RegStorage::FloatSolo64(reg1).GetReg(), base.GetReg(), offset);
1203 } else {
1204 NewLIR4(WIDE(kA64Ldp4ffXD), RegStorage::FloatSolo64(reg2).GetReg(),
1205 RegStorage::FloatSolo64(reg1).GetReg(), base.GetReg(), offset);
1206 }
1207 }
1208}
1209
1210// TODO(Arm64): consider using ld1 and st1?
1211void Arm64Mir2Lir::SpillFPRegs(RegStorage base, int offset, uint32_t reg_mask) {
1212 int reg1 = -1, reg2 = -1;
1213 const int reg_log2_size = 3;
1214
1215 for (offset = (offset >> reg_log2_size); reg_mask; offset += 2) {
1216 reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1217 if (UNLIKELY(reg2 < 0)) {
1218 NewLIR3(FWIDE(kA64Str3fXD), RegStorage::FloatSolo64(reg1).GetReg(), base.GetReg(), offset);
1219 } else {
1220 NewLIR4(WIDE(kA64Stp4ffXD), RegStorage::FloatSolo64(reg2).GetReg(),
1221 RegStorage::FloatSolo64(reg1).GetReg(), base.GetReg(), offset);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001222 }
1223 }
1224}
1225
Serban Constantinescu23abec92014-07-02 16:13:38 +01001226bool Arm64Mir2Lir::GenInlinedReverseBits(CallInfo* info, OpSize size) {
1227 ArmOpcode wide = (size == k64) ? WIDE(0) : UNWIDE(0);
1228 RegLocation rl_src_i = info->args[0];
1229 RegLocation rl_dest = (size == k64) ? InlineTargetWide(info) : InlineTarget(info); // result reg
1230 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1231 RegLocation rl_i = (size == k64) ? LoadValueWide(rl_src_i, kCoreReg) : LoadValue(rl_src_i, kCoreReg);
1232 NewLIR2(kA64Rbit2rr | wide, rl_result.reg.GetReg(), rl_i.reg.GetReg());
1233 (size == k64) ? StoreValueWide(rl_dest, rl_result) : StoreValue(rl_dest, rl_result);
1234 return true;
1235}
1236
Matteo Franchin43ec8732014-03-31 15:00:14 +01001237} // namespace art