blob: 8dad90aba6508ad7e0d631f24bf4273aeed4f4b9 [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"
22#include "entrypoints/quick/quick_entrypoints.h"
23#include "mirror/array.h"
24
25namespace art {
26
27LIR* Arm64Mir2Lir::OpCmpBranch(ConditionCode cond, RegStorage src1, RegStorage src2, LIR* target) {
28 OpRegReg(kOpCmp, src1, src2);
29 return OpCondBranch(cond, target);
30}
31
Matteo Franchine45fb9e2014-05-06 10:10:30 +010032// TODO(Arm64): remove this.
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
45 * csinc wC, wzr, wzr, eq
46 * csneg wC, wC, wC, le
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);
Serban Constantinescued65c5e2014-05-22 15:10:18 +010056 NewLIR4(WIDE(kA64Csinc4rrrc), rl_result.reg.GetReg(), rxzr, rxzr, kArmCondEq);
57 NewLIR4(WIDE(kA64Csneg4rrrc), rl_result.reg.GetReg(), rl_result.reg.GetReg(),
Matteo Franchine45fb9e2014-05-06 10:10:30 +010058 rl_result.reg.GetReg(), kArmCondLe);
Serban Constantinescued65c5e2014-05-22 15:10:18 +010059 StoreValueWide(rl_dest, rl_result);
60}
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 }
81 rl_shift = LoadValueWide(rl_shift, kCoreReg);
82 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
83 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
84 OpRegRegReg(op, rl_result.reg, rl_src1.reg, rl_shift.reg);
85 StoreValueWide(rl_dest, rl_result);
Matteo Franchin43ec8732014-03-31 15:00:14 +010086}
87
88void Arm64Mir2Lir::GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1,
Matteo Franchine45fb9e2014-05-06 10:10:30 +010089 int64_t val, ConditionCode ccode) {
Matteo Franchin43ec8732014-03-31 15:00:14 +010090 LIR* taken = &block_label_list_[bb->taken];
Matteo Franchin43ec8732014-03-31 15:00:14 +010091 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
Matteo Franchin43ec8732014-03-31 15:00:14 +010092
93 if (val == 0 && (ccode == kCondEq || ccode == kCondNe)) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +010094 ArmOpcode opcode = (ccode == kCondEq) ? kA64Cbz2rt : kA64Cbnz2rt;
95 LIR* branch = NewLIR2(WIDE(opcode), rl_src1.reg.GetLowReg(), 0);
96 branch->target = taken;
97 } else {
Serban Constantinescued65c5e2014-05-22 15:10:18 +010098 OpRegImm64(kOpCmp, rl_src1.reg, val);
Matteo Franchin43ec8732014-03-31 15:00:14 +010099 OpCondBranch(ccode, taken);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100100 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100101}
102
103void Arm64Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100104 // TODO(Arm64): implement this.
105 UNIMPLEMENTED(FATAL);
106
Matteo Franchin43ec8732014-03-31 15:00:14 +0100107 RegLocation rl_result;
108 RegLocation rl_src = mir_graph_->GetSrc(mir, 0);
109 RegLocation rl_dest = mir_graph_->GetDest(mir);
110 rl_src = LoadValue(rl_src, kCoreReg);
111 ConditionCode ccode = mir->meta.ccode;
112 if (mir->ssa_rep->num_uses == 1) {
113 // CONST case
114 int true_val = mir->dalvikInsn.vB;
115 int false_val = mir->dalvikInsn.vC;
116 rl_result = EvalLoc(rl_dest, kCoreReg, true);
117 // Change kCondNe to kCondEq for the special cases below.
118 if (ccode == kCondNe) {
119 ccode = kCondEq;
120 std::swap(true_val, false_val);
121 }
122 bool cheap_false_val = InexpensiveConstantInt(false_val);
123 if (cheap_false_val && ccode == kCondEq && (true_val == 0 || true_val == -1)) {
124 OpRegRegImm(kOpSub, rl_result.reg, rl_src.reg, -true_val);
125 DCHECK(last_lir_insn_->u.m.def_mask & ENCODE_CCODE);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100126 OpIT(true_val == 0 ? kCondNe : kCondUge, "");
Matteo Franchin43ec8732014-03-31 15:00:14 +0100127 LoadConstant(rl_result.reg, false_val);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100128 GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact
Matteo Franchin43ec8732014-03-31 15:00:14 +0100129 } else if (cheap_false_val && ccode == kCondEq && true_val == 1) {
130 OpRegRegImm(kOpRsub, rl_result.reg, rl_src.reg, 1);
131 DCHECK(last_lir_insn_->u.m.def_mask & ENCODE_CCODE);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100132 OpIT(kCondLs, "");
Matteo Franchin43ec8732014-03-31 15:00:14 +0100133 LoadConstant(rl_result.reg, false_val);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100134 GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact
Matteo Franchin43ec8732014-03-31 15:00:14 +0100135 } else if (cheap_false_val && InexpensiveConstantInt(true_val)) {
136 OpRegImm(kOpCmp, rl_src.reg, 0);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100137 OpIT(ccode, "E");
Matteo Franchin43ec8732014-03-31 15:00:14 +0100138 LoadConstant(rl_result.reg, true_val);
139 LoadConstant(rl_result.reg, false_val);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100140 GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact
Matteo Franchin43ec8732014-03-31 15:00:14 +0100141 } else {
142 // Unlikely case - could be tuned.
143 RegStorage t_reg1 = AllocTemp();
144 RegStorage t_reg2 = AllocTemp();
145 LoadConstant(t_reg1, true_val);
146 LoadConstant(t_reg2, false_val);
147 OpRegImm(kOpCmp, rl_src.reg, 0);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100148 OpIT(ccode, "E");
Matteo Franchin43ec8732014-03-31 15:00:14 +0100149 OpRegCopy(rl_result.reg, t_reg1);
150 OpRegCopy(rl_result.reg, t_reg2);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100151 GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact
Matteo Franchin43ec8732014-03-31 15:00:14 +0100152 }
153 } else {
154 // MOVE case
155 RegLocation rl_true = mir_graph_->reg_location_[mir->ssa_rep->uses[1]];
156 RegLocation rl_false = mir_graph_->reg_location_[mir->ssa_rep->uses[2]];
157 rl_true = LoadValue(rl_true, kCoreReg);
158 rl_false = LoadValue(rl_false, kCoreReg);
159 rl_result = EvalLoc(rl_dest, kCoreReg, true);
160 OpRegImm(kOpCmp, rl_src.reg, 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100161 if (rl_result.reg.GetReg() == rl_true.reg.GetReg()) { // Is the "true" case already in place?
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100162 OpIT(NegateComparison(ccode), "");
Matteo Franchin43ec8732014-03-31 15:00:14 +0100163 OpRegCopy(rl_result.reg, rl_false.reg);
164 } else if (rl_result.reg.GetReg() == rl_false.reg.GetReg()) { // False case in place?
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100165 OpIT(ccode, "");
Matteo Franchin43ec8732014-03-31 15:00:14 +0100166 OpRegCopy(rl_result.reg, rl_true.reg);
167 } else { // Normal - select between the two.
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100168 OpIT(ccode, "E");
Matteo Franchin43ec8732014-03-31 15:00:14 +0100169 OpRegCopy(rl_result.reg, rl_true.reg);
170 OpRegCopy(rl_result.reg, rl_false.reg);
171 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100172 GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact
Matteo Franchin43ec8732014-03-31 15:00:14 +0100173 }
174 StoreValue(rl_dest, rl_result);
175}
176
177void Arm64Mir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100178 // TODO(Arm64): implement this.
179 UNIMPLEMENTED(FATAL);
180
Matteo Franchin43ec8732014-03-31 15:00:14 +0100181 RegLocation rl_src1 = mir_graph_->GetSrcWide(mir, 0);
182 RegLocation rl_src2 = mir_graph_->GetSrcWide(mir, 2);
183 // Normalize such that if either operand is constant, src2 will be constant.
184 ConditionCode ccode = mir->meta.ccode;
185 if (rl_src1.is_const) {
186 std::swap(rl_src1, rl_src2);
187 ccode = FlipComparisonOrder(ccode);
188 }
189 if (rl_src2.is_const) {
190 RegLocation rl_temp = UpdateLocWide(rl_src2);
191 // Do special compare/branch against simple const operand if not already in registers.
192 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100193 if ((rl_temp.location != kLocPhysReg)
194 /*&& ((ModifiedImmediate(Low32Bits(val)) >= 0) && (ModifiedImmediate(High32Bits(val)) >= 0))*/) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100195 GenFusedLongCmpImmBranch(bb, rl_src1, val, ccode);
196 return;
197 }
198 }
199 LIR* taken = &block_label_list_[bb->taken];
200 LIR* not_taken = &block_label_list_[bb->fall_through];
201 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
202 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
203 OpRegReg(kOpCmp, rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh());
204 switch (ccode) {
205 case kCondEq:
206 OpCondBranch(kCondNe, not_taken);
207 break;
208 case kCondNe:
209 OpCondBranch(kCondNe, taken);
210 break;
211 case kCondLt:
212 OpCondBranch(kCondLt, taken);
213 OpCondBranch(kCondGt, not_taken);
214 ccode = kCondUlt;
215 break;
216 case kCondLe:
217 OpCondBranch(kCondLt, taken);
218 OpCondBranch(kCondGt, not_taken);
219 ccode = kCondLs;
220 break;
221 case kCondGt:
222 OpCondBranch(kCondGt, taken);
223 OpCondBranch(kCondLt, not_taken);
224 ccode = kCondHi;
225 break;
226 case kCondGe:
227 OpCondBranch(kCondGt, taken);
228 OpCondBranch(kCondLt, not_taken);
229 ccode = kCondUge;
230 break;
231 default:
232 LOG(FATAL) << "Unexpected ccode: " << ccode;
233 }
234 OpRegReg(kOpCmp, rl_src1.reg.GetLow(), rl_src2.reg.GetLow());
235 OpCondBranch(ccode, taken);
236}
237
238/*
239 * Generate a register comparison to an immediate and branch. Caller
240 * is responsible for setting branch target field.
241 */
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100242LIR* Arm64Mir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value,
243 LIR* target) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100244 LIR* branch;
245 ArmConditionCode arm_cond = ArmConditionEncoding(cond);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100246 if (check_value == 0 && (arm_cond == kArmCondEq || arm_cond == kArmCondNe)) {
247 ArmOpcode opcode = (arm_cond == kArmCondEq) ? kA64Cbz2rt : kA64Cbnz2rt;
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100248 ArmOpcode wide = reg.Is64Bit() ? WIDE(0) : UNWIDE(0);
249 branch = NewLIR2(opcode | wide, reg.GetReg(), 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100250 } else {
251 OpRegImm(kOpCmp, reg, check_value);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100252 branch = NewLIR2(kA64B2ct, arm_cond, 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100253 }
254 branch->target = target;
255 return branch;
256}
257
258LIR* Arm64Mir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100259 bool dest_is_fp = r_dest.IsFloat();
260 bool src_is_fp = r_src.IsFloat();
261 ArmOpcode opcode = kA64Brk1d;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100262 LIR* res;
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100263
264 if (LIKELY(dest_is_fp == src_is_fp)) {
265 if (LIKELY(!dest_is_fp)) {
266 // Core/core copy.
267 // Copies involving the sp register require a different instruction.
268 opcode = UNLIKELY(A64_REG_IS_SP(r_dest.GetReg())) ? kA64Add4RRdT : kA64Mov2rr;
269
270 // TODO(Arm64): kA64Add4RRdT formally has 4 args, but is used as a 2 args instruction.
271 // This currently works because the other arguments are set to 0 by default. We should
272 // rather introduce an alias kA64Mov2RR.
273
274 // core/core copy. Do a x/x copy only if both registers are x.
275 if (r_dest.Is64Bit() && r_src.Is64Bit()) {
276 opcode = WIDE(opcode);
277 }
278 } else {
279 // Float/float copy.
280 bool dest_is_double = r_dest.IsDouble();
281 bool src_is_double = r_src.IsDouble();
282
283 // We do not do float/double or double/float casts here.
284 DCHECK_EQ(dest_is_double, src_is_double);
285
286 // Homogeneous float/float copy.
287 opcode = (dest_is_double) ? FWIDE(kA64Fmov2ff) : kA64Fmov2ff;
288 }
289 } else {
290 // Inhomogeneous register copy.
291 if (dest_is_fp) {
292 if (r_dest.IsDouble()) {
293 opcode = kA64Fmov2Sx;
294 } else {
295 DCHECK(r_src.IsSingle());
296 opcode = kA64Fmov2sw;
297 }
298 } else {
299 if (r_src.IsDouble()) {
300 opcode = kA64Fmov2xS;
301 } else {
302 DCHECK(r_dest.Is32Bit());
303 opcode = kA64Fmov2ws;
304 }
305 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100306 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100307
Matteo Franchin43ec8732014-03-31 15:00:14 +0100308 res = RawLIR(current_dalvik_offset_, opcode, r_dest.GetReg(), r_src.GetReg());
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100309
Matteo Franchin43ec8732014-03-31 15:00:14 +0100310 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
311 res->flags.is_nop = true;
312 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100313
Matteo Franchin43ec8732014-03-31 15:00:14 +0100314 return res;
315}
316
317void Arm64Mir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
318 if (r_dest != r_src) {
319 LIR* res = OpRegCopyNoInsert(r_dest, r_src);
320 AppendLIR(res);
321 }
322}
323
324void Arm64Mir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100325 OpRegCopy(r_dest, r_src);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100326}
327
328// Table of magic divisors
329struct MagicTable {
330 uint32_t magic;
331 uint32_t shift;
332 DividePattern pattern;
333};
334
335static const MagicTable magic_table[] = {
336 {0, 0, DivideNone}, // 0
337 {0, 0, DivideNone}, // 1
338 {0, 0, DivideNone}, // 2
339 {0x55555556, 0, Divide3}, // 3
340 {0, 0, DivideNone}, // 4
341 {0x66666667, 1, Divide5}, // 5
342 {0x2AAAAAAB, 0, Divide3}, // 6
343 {0x92492493, 2, Divide7}, // 7
344 {0, 0, DivideNone}, // 8
345 {0x38E38E39, 1, Divide5}, // 9
346 {0x66666667, 2, Divide5}, // 10
347 {0x2E8BA2E9, 1, Divide5}, // 11
348 {0x2AAAAAAB, 1, Divide5}, // 12
349 {0x4EC4EC4F, 2, Divide5}, // 13
350 {0x92492493, 3, Divide7}, // 14
351 {0x88888889, 3, Divide7}, // 15
352};
353
354// Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
355bool Arm64Mir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
356 RegLocation rl_src, RegLocation rl_dest, int lit) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100357 // TODO(Arm64): fix this for Arm64. Note: may be worth revisiting the magic table.
358 // It should be possible subtracting one from all its entries, and using smaddl
359 // to counteract this. The advantage is that integers should then be easier to
360 // encode as logical immediates (0x55555555 rather than 0x55555556).
361 UNIMPLEMENTED(FATAL);
362
Matteo Franchin43ec8732014-03-31 15:00:14 +0100363 if ((lit < 0) || (lit >= static_cast<int>(sizeof(magic_table)/sizeof(magic_table[0])))) {
364 return false;
365 }
366 DividePattern pattern = magic_table[lit].pattern;
367 if (pattern == DivideNone) {
368 return false;
369 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100370 // Tuning: add rem patterns
371 if (!is_div) {
372 return false;
373 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100374
375 RegStorage r_magic = AllocTemp();
376 LoadConstant(r_magic, magic_table[lit].magic);
377 rl_src = LoadValue(rl_src, kCoreReg);
378 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
379 RegStorage r_hi = AllocTemp();
380 RegStorage r_lo = AllocTemp();
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100381 NewLIR4(kA64Smaddl4xwwx, r_lo.GetReg(), r_magic.GetReg(), rl_src.reg.GetReg(), rxzr);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100382 switch (pattern) {
383 case Divide3:
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100384 OpRegRegRegShift(kOpSub, rl_result.reg, r_hi, rl_src.reg, EncodeShift(kA64Asr, 31));
Matteo Franchin43ec8732014-03-31 15:00:14 +0100385 break;
386 case Divide5:
387 OpRegRegImm(kOpAsr, r_lo, rl_src.reg, 31);
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100388 OpRegRegRegShift(kOpRsub, rl_result.reg, r_lo, r_hi, EncodeShift(kA64Asr, magic_table[lit].shift));
Matteo Franchin43ec8732014-03-31 15:00:14 +0100389 break;
390 case Divide7:
391 OpRegReg(kOpAdd, r_hi, rl_src.reg);
392 OpRegRegImm(kOpAsr, r_lo, rl_src.reg, 31);
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100393 OpRegRegRegShift(kOpRsub, rl_result.reg, r_lo, r_hi, EncodeShift(kA64Asr, magic_table[lit].shift));
Matteo Franchin43ec8732014-03-31 15:00:14 +0100394 break;
395 default:
396 LOG(FATAL) << "Unexpected pattern: " << pattern;
397 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100398 StoreValue(rl_dest, rl_result);
399 return true;
400}
401
Matteo Franchin43ec8732014-03-31 15:00:14 +0100402bool Arm64Mir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100403 LOG(FATAL) << "Unexpected use of EasyMultiply for Arm64";
404 return false;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100405}
406
407RegLocation Arm64Mir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
408 RegLocation rl_src2, bool is_div, bool check_zero) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100409 LOG(FATAL) << "Unexpected use of GenDivRem for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +0100410 return rl_dest;
411}
412
413RegLocation Arm64Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100414 LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +0100415 return rl_dest;
416}
417
418RegLocation Arm64Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit, bool is_div) {
419 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
420
421 // Put the literal in a temp.
422 RegStorage lit_temp = AllocTemp();
423 LoadConstant(lit_temp, lit);
424 // Use the generic case for div/rem with arg2 in a register.
425 // TODO: The literal temp can be freed earlier during a modulus to reduce reg pressure.
426 rl_result = GenDivRem(rl_result, reg1, lit_temp, is_div);
427 FreeTemp(lit_temp);
428
429 return rl_result;
430}
431
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100432RegLocation Arm64Mir2Lir::GenDivRem(RegLocation rl_dest, RegStorage r_src1, RegStorage r_src2,
Matteo Franchin43ec8732014-03-31 15:00:14 +0100433 bool is_div) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100434 CHECK_EQ(r_src1.Is64Bit(), r_src2.Is64Bit());
435
Matteo Franchin43ec8732014-03-31 15:00:14 +0100436 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
437 if (is_div) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100438 OpRegRegReg(kOpDiv, rl_result.reg, r_src1, r_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100439 } else {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100440 // temp = r_src1 / r_src2
441 // dest = r_src1 - temp * r_src2
442 RegStorage temp;
443 ArmOpcode wide;
444 if (rl_result.reg.Is64Bit()) {
445 temp = AllocTempWide();
446 wide = WIDE(0);
447 } else {
448 temp = AllocTemp();
449 wide = UNWIDE(0);
450 }
451 OpRegRegReg(kOpDiv, temp, r_src1, r_src2);
452 NewLIR4(kA64Msub4rrrr | wide, rl_result.reg.GetReg(), temp.GetReg(),
453 r_src1.GetReg(), r_src2.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100454 FreeTemp(temp);
455 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100456 return rl_result;
457}
458
459bool Arm64Mir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100460 // TODO(Arm64): implement this.
461 UNIMPLEMENTED(FATAL);
462
Matteo Franchin43ec8732014-03-31 15:00:14 +0100463 DCHECK_EQ(cu_->instruction_set, kThumb2);
464 RegLocation rl_src1 = info->args[0];
465 RegLocation rl_src2 = info->args[1];
466 rl_src1 = LoadValue(rl_src1, kCoreReg);
467 rl_src2 = LoadValue(rl_src2, kCoreReg);
468 RegLocation rl_dest = InlineTarget(info);
469 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
470 OpRegReg(kOpCmp, rl_src1.reg, rl_src2.reg);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100471 OpIT((is_min) ? kCondGt : kCondLt, "E");
Matteo Franchin43ec8732014-03-31 15:00:14 +0100472 OpRegReg(kOpMov, rl_result.reg, rl_src2.reg);
473 OpRegReg(kOpMov, rl_result.reg, rl_src1.reg);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100474 GenBarrier();
Matteo Franchin43ec8732014-03-31 15:00:14 +0100475 StoreValue(rl_dest, rl_result);
476 return true;
477}
478
479bool Arm64Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100480 // TODO(Arm64): implement this.
481 UNIMPLEMENTED(WARNING);
482
Matteo Franchin43ec8732014-03-31 15:00:14 +0100483 RegLocation rl_src_address = info->args[0]; // long address
484 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1]
485 RegLocation rl_dest = InlineTarget(info);
486 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
487 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
488 if (size == k64) {
489 // Fake unaligned LDRD by two unaligned LDR instructions on ARMv7 with SCTLR.A set to 0.
490 if (rl_address.reg.GetReg() != rl_result.reg.GetLowReg()) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100491 LoadWordDisp(rl_address.reg, 0, rl_result.reg.GetLow());
492 LoadWordDisp(rl_address.reg, 4, rl_result.reg.GetHigh());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100493 } else {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100494 LoadWordDisp(rl_address.reg, 4, rl_result.reg.GetHigh());
495 LoadWordDisp(rl_address.reg, 0, rl_result.reg.GetLow());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100496 }
497 StoreValueWide(rl_dest, rl_result);
498 } else {
499 DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
500 // Unaligned load with LDR and LDRSH is allowed on ARMv7 with SCTLR.A set to 0.
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100501 LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100502 StoreValue(rl_dest, rl_result);
503 }
504 return true;
505}
506
507bool Arm64Mir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100508 // TODO(Arm64): implement this.
509 UNIMPLEMENTED(WARNING);
510
Matteo Franchin43ec8732014-03-31 15:00:14 +0100511 RegLocation rl_src_address = info->args[0]; // long address
512 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1]
513 RegLocation rl_src_value = info->args[2]; // [size] value
514 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
515 if (size == k64) {
516 // Fake unaligned STRD by two unaligned STR instructions on ARMv7 with SCTLR.A set to 0.
517 RegLocation rl_value = LoadValueWide(rl_src_value, kCoreReg);
518 StoreBaseDisp(rl_address.reg, 0, rl_value.reg.GetLow(), k32);
519 StoreBaseDisp(rl_address.reg, 4, rl_value.reg.GetHigh(), k32);
520 } else {
521 DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
522 // Unaligned store with STR and STRSH is allowed on ARMv7 with SCTLR.A set to 0.
523 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
524 StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size);
525 }
526 return true;
527}
528
529void Arm64Mir2Lir::OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale, int offset) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100530 LOG(FATAL) << "Unexpected use of OpLea for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +0100531}
532
Andreas Gampe2f244e92014-05-08 03:35:25 -0700533void Arm64Mir2Lir::OpTlsCmp(ThreadOffset<4> offset, int val) {
534 UNIMPLEMENTED(FATAL) << "Should not be used.";
535}
536
537void Arm64Mir2Lir::OpTlsCmp(ThreadOffset<8> offset, int val) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100538 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +0100539}
540
541bool Arm64Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100542 // TODO(Arm64): implement this.
543 UNIMPLEMENTED(WARNING);
544
Matteo Franchin43ec8732014-03-31 15:00:14 +0100545 DCHECK_EQ(cu_->instruction_set, kThumb2);
546 // Unused - RegLocation rl_src_unsafe = info->args[0];
547 RegLocation rl_src_obj = info->args[1]; // Object - known non-null
548 RegLocation rl_src_offset = info->args[2]; // long low
549 rl_src_offset = NarrowRegLoc(rl_src_offset); // ignore high half in info->args[3]
550 RegLocation rl_src_expected = info->args[4]; // int, long or Object
551 // If is_long, high half is in info->args[5]
552 RegLocation rl_src_new_value = info->args[is_long ? 6 : 5]; // int, long or Object
553 // If is_long, high half is in info->args[7]
554 RegLocation rl_dest = InlineTarget(info); // boolean place for result
555
556 // We have only 5 temporary registers available and actually only 4 if the InlineTarget
557 // above locked one of the temps. For a straightforward CAS64 we need 7 registers:
558 // r_ptr (1), new_value (2), expected(2) and ldrexd result (2). If neither expected nor
559 // new_value is in a non-temp core register we shall reload them in the ldrex/strex loop
560 // into the same temps, reducing the number of required temps down to 5. We shall work
561 // around the potentially locked temp by using LR for r_ptr, unconditionally.
562 // TODO: Pass information about the need for more temps to the stack frame generation
563 // code so that we can rely on being able to allocate enough temps.
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100564 DCHECK(!GetRegInfo(rs_rA64_LR)->IsTemp());
565 MarkTemp(rs_rA64_LR);
566 FreeTemp(rs_rA64_LR);
567 LockTemp(rs_rA64_LR);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100568 bool load_early = true;
569 if (is_long) {
570 RegStorage expected_reg = rl_src_expected.reg.IsPair() ? rl_src_expected.reg.GetLow() :
571 rl_src_expected.reg;
572 RegStorage new_val_reg = rl_src_new_value.reg.IsPair() ? rl_src_new_value.reg.GetLow() :
573 rl_src_new_value.reg;
574 bool expected_is_core_reg = rl_src_expected.location == kLocPhysReg && !expected_reg.IsFloat();
575 bool new_value_is_core_reg = rl_src_new_value.location == kLocPhysReg && !new_val_reg.IsFloat();
576 bool expected_is_good_reg = expected_is_core_reg && !IsTemp(expected_reg);
577 bool new_value_is_good_reg = new_value_is_core_reg && !IsTemp(new_val_reg);
578
579 if (!expected_is_good_reg && !new_value_is_good_reg) {
580 // None of expected/new_value is non-temp reg, need to load both late
581 load_early = false;
582 // Make sure they are not in the temp regs and the load will not be skipped.
583 if (expected_is_core_reg) {
584 FlushRegWide(rl_src_expected.reg);
585 ClobberSReg(rl_src_expected.s_reg_low);
586 ClobberSReg(GetSRegHi(rl_src_expected.s_reg_low));
587 rl_src_expected.location = kLocDalvikFrame;
588 }
589 if (new_value_is_core_reg) {
590 FlushRegWide(rl_src_new_value.reg);
591 ClobberSReg(rl_src_new_value.s_reg_low);
592 ClobberSReg(GetSRegHi(rl_src_new_value.s_reg_low));
593 rl_src_new_value.location = kLocDalvikFrame;
594 }
595 }
596 }
597
598 // Release store semantics, get the barrier out of the way. TODO: revisit
599 GenMemBarrier(kStoreLoad);
600
601 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
602 RegLocation rl_new_value;
603 if (!is_long) {
604 rl_new_value = LoadValue(rl_src_new_value, kCoreReg);
605 } else if (load_early) {
606 rl_new_value = LoadValueWide(rl_src_new_value, kCoreReg);
607 }
608
609 if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
610 // Mark card for object assuming new value is stored.
611 MarkGCCard(rl_new_value.reg, rl_object.reg);
612 }
613
614 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
615
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100616 RegStorage r_ptr = rs_rA64_LR;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100617 OpRegRegReg(kOpAdd, r_ptr, rl_object.reg, rl_offset.reg);
618
619 // Free now unneeded rl_object and rl_offset to give more temps.
620 ClobberSReg(rl_object.s_reg_low);
621 FreeTemp(rl_object.reg);
622 ClobberSReg(rl_offset.s_reg_low);
623 FreeTemp(rl_offset.reg);
624
625 RegLocation rl_expected;
626 if (!is_long) {
627 rl_expected = LoadValue(rl_src_expected, kCoreReg);
628 } else if (load_early) {
629 rl_expected = LoadValueWide(rl_src_expected, kCoreReg);
630 } else {
631 // NOTE: partially defined rl_expected & rl_new_value - but we just want the regs.
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100632 int low_reg = AllocTemp().GetReg();
633 int high_reg = AllocTemp().GetReg();
634 rl_new_value.reg = RegStorage(RegStorage::k64BitPair, low_reg, high_reg);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100635 rl_expected = rl_new_value;
636 }
637
638 // do {
639 // tmp = [r_ptr] - expected;
640 // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
641 // result = tmp != 0;
642
643 RegStorage r_tmp = AllocTemp();
644 LIR* target = NewLIR0(kPseudoTargetLabel);
645
Matteo Franchin43ec8732014-03-31 15:00:14 +0100646 if (is_long) {
647 RegStorage r_tmp_high = AllocTemp();
648 if (!load_early) {
649 LoadValueDirectWide(rl_src_expected, rl_expected.reg);
650 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100651 NewLIR3(kA64Ldxr2rX, r_tmp.GetReg(), r_tmp_high.GetReg(), r_ptr.GetReg());
Matteo Franchin43ec8732014-03-31 15:00:14 +0100652 OpRegReg(kOpSub, r_tmp, rl_expected.reg.GetLow());
653 OpRegReg(kOpSub, r_tmp_high, rl_expected.reg.GetHigh());
654 if (!load_early) {
655 LoadValueDirectWide(rl_src_new_value, rl_new_value.reg);
656 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100657
658 LIR* branch1 = OpCmpImmBranch(kCondNe, r_tmp, 0, NULL);
659 LIR* branch2 = OpCmpImmBranch(kCondNe, r_tmp_high, 0, NULL);
660 NewLIR4(WIDE(kA64Stxr3wrX) /* eq */, r_tmp.GetReg(), rl_new_value.reg.GetReg(),
661 rl_new_value.reg.GetHighReg(), r_ptr.GetReg());
662 LIR* target2 = NewLIR0(kPseudoTargetLabel);
663 branch1->target = target2;
664 branch2->target = target2;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100665 FreeTemp(r_tmp_high); // Now unneeded
666
Matteo Franchin43ec8732014-03-31 15:00:14 +0100667 } else {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100668 NewLIR3(kA64Ldxr2rX, r_tmp.GetReg(), r_ptr.GetReg(), 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100669 OpRegReg(kOpSub, r_tmp, rl_expected.reg);
670 DCHECK(last_lir_insn_->u.m.def_mask & ENCODE_CCODE);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100671 OpIT(kCondEq, "T");
672 NewLIR4(kA64Stxr3wrX /* eq */, r_tmp.GetReg(), rl_new_value.reg.GetReg(), r_ptr.GetReg(), 0);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100673 }
674
675 // Still one conditional left from OpIT(kCondEq, "T") from either branch
676 OpRegImm(kOpCmp /* eq */, r_tmp, 1);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100677 OpCondBranch(kCondEq, target);
678
679 if (!load_early) {
680 FreeTemp(rl_expected.reg); // Now unneeded.
681 }
682
683 // result := (tmp1 != 0) ? 0 : 1;
684 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
685 OpRegRegImm(kOpRsub, rl_result.reg, r_tmp, 1);
686 DCHECK(last_lir_insn_->u.m.def_mask & ENCODE_CCODE);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100687 OpIT(kCondUlt, "");
Matteo Franchin43ec8732014-03-31 15:00:14 +0100688 LoadConstant(rl_result.reg, 0); /* cc */
689 FreeTemp(r_tmp); // Now unneeded.
Matteo Franchin43ec8732014-03-31 15:00:14 +0100690
691 StoreValue(rl_dest, rl_result);
692
693 // Now, restore lr to its non-temp status.
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100694 Clobber(rs_rA64_LR);
695 UnmarkTemp(rs_rA64_LR);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100696 return true;
697}
698
699LIR* Arm64Mir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100700 return RawLIR(current_dalvik_offset_, WIDE(kA64Ldr2rp), reg.GetReg(), 0, 0, 0, 0, target);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100701}
702
703LIR* Arm64Mir2Lir::OpVldm(RegStorage r_base, int count) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100704 LOG(FATAL) << "Unexpected use of OpVldm for Arm64";
705 return NULL;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100706}
707
708LIR* Arm64Mir2Lir::OpVstm(RegStorage r_base, int count) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100709 LOG(FATAL) << "Unexpected use of OpVstm for Arm64";
710 return NULL;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100711}
712
713void Arm64Mir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
714 RegLocation rl_result, int lit,
715 int first_bit, int second_bit) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100716 OpRegRegRegShift(kOpAdd, rl_result.reg, rl_src.reg, rl_src.reg, EncodeShift(kA64Lsl, second_bit - first_bit));
Matteo Franchin43ec8732014-03-31 15:00:14 +0100717 if (first_bit != 0) {
718 OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit);
719 }
720}
721
722void Arm64Mir2Lir::GenDivZeroCheckWide(RegStorage reg) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100723 LOG(FATAL) << "Unexpected use of GenDivZero for Arm64";
Matteo Franchin43ec8732014-03-31 15:00:14 +0100724}
725
726// Test suspend flag, return target of taken suspend branch
727LIR* Arm64Mir2Lir::OpTestSuspend(LIR* target) {
Zheng Xu48241e72014-05-23 11:52:42 +0800728 // FIXME: Define rA64_SUSPEND as w19, when we do not need two copies of reserved register.
729 // Note: The opcode is not set as wide, so actually we are using the 32-bit version register.
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100730 NewLIR3(kA64Subs3rRd, rA64_SUSPEND, rA64_SUSPEND, 1);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100731 return OpCondBranch((target == NULL) ? kCondEq : kCondNe, target);
732}
733
734// Decrement register and branch on condition
735LIR* Arm64Mir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) {
736 // Combine sub & test using sub setflags encoding here
737 OpRegRegImm(kOpSub, reg, reg, 1); // For value == 1, this should set flags.
738 DCHECK(last_lir_insn_->u.m.def_mask & ENCODE_CCODE);
739 return OpCondBranch(c_code, target);
740}
741
Andreas Gampeb14329f2014-05-15 11:16:06 -0700742bool Arm64Mir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100743#if ANDROID_SMP != 0
744 // Start off with using the last LIR as the barrier. If it is not enough, then we will generate one.
745 LIR* barrier = last_lir_insn_;
746
747 int dmb_flavor;
748 // TODO: revisit Arm barrier kinds
749 switch (barrier_kind) {
750 case kLoadStore: dmb_flavor = kISH; break;
751 case kLoadLoad: dmb_flavor = kISH; break;
752 case kStoreStore: dmb_flavor = kISHST; break;
753 case kStoreLoad: dmb_flavor = kISH; break;
754 default:
755 LOG(FATAL) << "Unexpected MemBarrierKind: " << barrier_kind;
756 dmb_flavor = kSY; // quiet gcc.
757 break;
758 }
759
Andreas Gampeb14329f2014-05-15 11:16:06 -0700760 bool ret = false;
761
Matteo Franchin43ec8732014-03-31 15:00:14 +0100762 // If the same barrier already exists, don't generate another.
763 if (barrier == nullptr
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100764 || (barrier->opcode != kA64Dmb1B || barrier->operands[0] != dmb_flavor)) {
765 barrier = NewLIR1(kA64Dmb1B, dmb_flavor);
Andreas Gampeb14329f2014-05-15 11:16:06 -0700766 ret = true;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100767 }
768
769 // At this point we must have a memory barrier. Mark it as a scheduling barrier as well.
770 DCHECK(!barrier->flags.use_def_invalid);
771 barrier->u.m.def_mask = ENCODE_ALL;
Andreas Gampeb14329f2014-05-15 11:16:06 -0700772 return ret;
773#else
774 return false;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100775#endif
776}
777
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100778void Arm64Mir2Lir::GenIntToLong(RegLocation rl_dest, RegLocation rl_src) {
779 RegLocation rl_result;
780
781 rl_src = LoadValue(rl_src, kCoreReg);
782 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
783 NewLIR4(WIDE(kA64Sbfm4rrdd), rl_result.reg.GetReg(), rl_src.reg.GetReg(), 0, 31);
784 StoreValueWide(rl_dest, rl_result);
785}
786
787void Arm64Mir2Lir::GenDivRemLong(Instruction::Code opcode, RegLocation rl_dest,
788 RegLocation rl_src1, RegLocation rl_src2, bool is_div) {
789 RegLocation rl_result;
790 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
791 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
792 GenDivZeroCheck(rl_src2.reg);
793 rl_result = GenDivRem(rl_dest, rl_src1.reg, rl_src2.reg, is_div);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100794 StoreValueWide(rl_dest, rl_result);
795}
796
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100797void Arm64Mir2Lir::GenLongOp(OpKind op, RegLocation rl_dest, RegLocation rl_src1,
798 RegLocation rl_src2) {
799 RegLocation rl_result;
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100800
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100801 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
802 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
803 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100804 OpRegRegRegShift(op, rl_result.reg, rl_src1.reg, rl_src2.reg, ENCODE_NO_SHIFT);
805 StoreValueWide(rl_dest, rl_result);
806}
807
808void Arm64Mir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
809 RegLocation rl_result;
810
811 rl_src = LoadValueWide(rl_src, kCoreReg);
812 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
813 OpRegRegShift(kOpNeg, rl_result.reg, rl_src.reg, ENCODE_NO_SHIFT);
814 StoreValueWide(rl_dest, rl_result);
815}
816
817void Arm64Mir2Lir::GenNotLong(RegLocation rl_dest, RegLocation rl_src) {
818 RegLocation rl_result;
819
820 rl_src = LoadValueWide(rl_src, kCoreReg);
821 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
822 OpRegRegShift(kOpMvn, rl_result.reg, rl_src.reg, ENCODE_NO_SHIFT);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100823 StoreValueWide(rl_dest, rl_result);
824}
825
Matteo Franchin43ec8732014-03-31 15:00:14 +0100826void Arm64Mir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest,
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100827 RegLocation rl_src1, RegLocation rl_src2) {
828 GenLongOp(kOpMul, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100829}
830
831void Arm64Mir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100832 RegLocation rl_src2) {
833 GenLongOp(kOpAdd, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100834}
835
836void Arm64Mir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
837 RegLocation rl_src2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100838 GenLongOp(kOpSub, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100839}
840
841void Arm64Mir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
842 RegLocation rl_src2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100843 GenLongOp(kOpAnd, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100844}
845
846void Arm64Mir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
847 RegLocation rl_src2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100848 GenLongOp(kOpOr, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100849}
850
851void Arm64Mir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
852 RegLocation rl_src2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100853 GenLongOp(kOpXor, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100854}
855
856/*
857 * Generate array load
858 */
859void Arm64Mir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
860 RegLocation rl_index, RegLocation rl_dest, int scale) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100861 // TODO(Arm64): check this.
862 UNIMPLEMENTED(WARNING);
863
Matteo Franchin43ec8732014-03-31 15:00:14 +0100864 RegisterClass reg_class = RegClassBySize(size);
865 int len_offset = mirror::Array::LengthOffset().Int32Value();
866 int data_offset;
867 RegLocation rl_result;
868 bool constant_index = rl_index.is_const;
869 rl_array = LoadValue(rl_array, kCoreReg);
870 if (!constant_index) {
871 rl_index = LoadValue(rl_index, kCoreReg);
872 }
873
874 if (rl_dest.wide) {
875 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
876 } else {
877 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
878 }
879
880 // If index is constant, just fold it into the data offset
881 if (constant_index) {
882 data_offset += mir_graph_->ConstantValue(rl_index) << scale;
883 }
884
885 /* null object? */
886 GenNullCheck(rl_array.reg, opt_flags);
887
888 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
889 RegStorage reg_len;
890 if (needs_range_check) {
891 reg_len = AllocTemp();
892 /* Get len */
893 Load32Disp(rl_array.reg, len_offset, reg_len);
894 MarkPossibleNullPointerException(opt_flags);
895 } else {
896 ForceImplicitNullCheck(rl_array.reg, opt_flags);
897 }
898 if (rl_dest.wide || rl_dest.fp || constant_index) {
899 RegStorage reg_ptr;
900 if (constant_index) {
901 reg_ptr = rl_array.reg; // NOTE: must not alter reg_ptr in constant case.
902 } else {
903 // No special indexed operation, lea + load w/ displacement
904 reg_ptr = AllocTemp();
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100905 OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.reg, rl_index.reg, EncodeShift(kA64Lsl, scale));
Matteo Franchin43ec8732014-03-31 15:00:14 +0100906 FreeTemp(rl_index.reg);
907 }
908 rl_result = EvalLoc(rl_dest, reg_class, true);
909
910 if (needs_range_check) {
911 if (constant_index) {
912 GenArrayBoundsCheck(mir_graph_->ConstantValue(rl_index), reg_len);
913 } else {
914 GenArrayBoundsCheck(rl_index.reg, reg_len);
915 }
916 FreeTemp(reg_len);
917 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100918 LoadBaseDisp(reg_ptr, data_offset, rl_result.reg, size);
Vladimir Marko455759b2014-05-06 20:49:36 +0100919 MarkPossibleNullPointerException(opt_flags);
920 if (!constant_index) {
921 FreeTemp(reg_ptr);
922 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100923 if (rl_dest.wide) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100924 StoreValueWide(rl_dest, rl_result);
925 } else {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100926 StoreValue(rl_dest, rl_result);
927 }
928 } else {
929 // Offset base, then use indexed load
930 RegStorage reg_ptr = AllocTemp();
931 OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
932 FreeTemp(rl_array.reg);
933 rl_result = EvalLoc(rl_dest, reg_class, true);
934
935 if (needs_range_check) {
936 GenArrayBoundsCheck(rl_index.reg, reg_len);
937 FreeTemp(reg_len);
938 }
939 LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
940 MarkPossibleNullPointerException(opt_flags);
941 FreeTemp(reg_ptr);
942 StoreValue(rl_dest, rl_result);
943 }
944}
945
946/*
947 * Generate array store
948 *
949 */
950void Arm64Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
951 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100952 // TODO(Arm64): check this.
953 UNIMPLEMENTED(WARNING);
954
Matteo Franchin43ec8732014-03-31 15:00:14 +0100955 RegisterClass reg_class = RegClassBySize(size);
956 int len_offset = mirror::Array::LengthOffset().Int32Value();
957 bool constant_index = rl_index.is_const;
958
959 int data_offset;
960 if (size == k64 || size == kDouble) {
961 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
962 } else {
963 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
964 }
965
966 // If index is constant, just fold it into the data offset.
967 if (constant_index) {
968 data_offset += mir_graph_->ConstantValue(rl_index) << scale;
969 }
970
971 rl_array = LoadValue(rl_array, kCoreReg);
972 if (!constant_index) {
973 rl_index = LoadValue(rl_index, kCoreReg);
974 }
975
976 RegStorage reg_ptr;
977 bool allocated_reg_ptr_temp = false;
978 if (constant_index) {
979 reg_ptr = rl_array.reg;
980 } else if (IsTemp(rl_array.reg) && !card_mark) {
981 Clobber(rl_array.reg);
982 reg_ptr = rl_array.reg;
983 } else {
984 allocated_reg_ptr_temp = true;
985 reg_ptr = AllocTemp();
986 }
987
988 /* null object? */
989 GenNullCheck(rl_array.reg, opt_flags);
990
991 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
992 RegStorage reg_len;
993 if (needs_range_check) {
994 reg_len = AllocTemp();
995 // NOTE: max live temps(4) here.
996 /* Get len */
997 Load32Disp(rl_array.reg, len_offset, reg_len);
998 MarkPossibleNullPointerException(opt_flags);
999 } else {
1000 ForceImplicitNullCheck(rl_array.reg, opt_flags);
1001 }
1002 /* at this point, reg_ptr points to array, 2 live temps */
1003 if (rl_src.wide || rl_src.fp || constant_index) {
1004 if (rl_src.wide) {
1005 rl_src = LoadValueWide(rl_src, reg_class);
1006 } else {
1007 rl_src = LoadValue(rl_src, reg_class);
1008 }
1009 if (!constant_index) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001010 OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.reg, rl_index.reg, EncodeShift(kA64Lsl, scale));
Matteo Franchin43ec8732014-03-31 15:00:14 +01001011 }
1012 if (needs_range_check) {
1013 if (constant_index) {
1014 GenArrayBoundsCheck(mir_graph_->ConstantValue(rl_index), reg_len);
1015 } else {
1016 GenArrayBoundsCheck(rl_index.reg, reg_len);
1017 }
1018 FreeTemp(reg_len);
1019 }
1020
Vladimir Marko455759b2014-05-06 20:49:36 +01001021 StoreBaseDisp(reg_ptr, data_offset, rl_src.reg, size);
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 }
1031 StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
1032 MarkPossibleNullPointerException(opt_flags);
1033 }
1034 if (allocated_reg_ptr_temp) {
1035 FreeTemp(reg_ptr);
1036 }
1037 if (card_mark) {
1038 MarkGCCard(rl_src.reg, rl_array.reg);
1039 }
1040}
1041
Matteo Franchin43ec8732014-03-31 15:00:14 +01001042void Arm64Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode,
1043 RegLocation rl_dest, RegLocation rl_src, RegLocation rl_shift) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001044 OpKind op = kOpBkpt;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001045 // Per spec, we only care about low 6 bits of shift amount.
1046 int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f;
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001047 rl_src = LoadValueWide(rl_src, kCoreReg);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001048 if (shift_amount == 0) {
1049 StoreValueWide(rl_dest, rl_src);
1050 return;
1051 }
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001052
1053 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001054 switch (opcode) {
1055 case Instruction::SHL_LONG:
1056 case Instruction::SHL_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001057 op = kOpLsl;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001058 break;
1059 case Instruction::SHR_LONG:
1060 case Instruction::SHR_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001061 op = kOpAsr;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001062 break;
1063 case Instruction::USHR_LONG:
1064 case Instruction::USHR_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001065 op = kOpLsr;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001066 break;
1067 default:
1068 LOG(FATAL) << "Unexpected case";
1069 }
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001070 OpRegRegImm(op, rl_result.reg, rl_src.reg, shift_amount);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001071 StoreValueWide(rl_dest, rl_result);
1072}
1073
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001074void Arm64Mir2Lir::GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
1075 RegLocation rl_src1, RegLocation rl_src2) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001076 if ((opcode == Instruction::SUB_LONG) || (opcode == Instruction::SUB_LONG_2ADDR)) {
Matteo Franchin43ec8732014-03-31 15:00:14 +01001077 if (!rl_src2.is_const) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001078 return GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001079 }
1080 } else {
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001081 // Associativity.
Matteo Franchin43ec8732014-03-31 15:00:14 +01001082 if (!rl_src2.is_const) {
1083 DCHECK(rl_src1.is_const);
1084 std::swap(rl_src1, rl_src2);
1085 }
1086 }
Matteo Franchin43ec8732014-03-31 15:00:14 +01001087 DCHECK(rl_src2.is_const);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001088
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001089 OpKind op = kOpBkpt;
1090 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
1091
Matteo Franchin43ec8732014-03-31 15:00:14 +01001092 switch (opcode) {
1093 case Instruction::ADD_LONG:
1094 case Instruction::ADD_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001095 op = kOpAdd;
1096 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001097 case Instruction::SUB_LONG:
1098 case Instruction::SUB_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001099 op = kOpSub;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001100 break;
1101 case Instruction::AND_LONG:
1102 case Instruction::AND_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001103 op = kOpAnd;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001104 break;
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001105 case Instruction::OR_LONG:
1106 case Instruction::OR_LONG_2ADDR:
1107 op = kOpOr;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001108 break;
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001109 case Instruction::XOR_LONG:
1110 case Instruction::XOR_LONG_2ADDR:
1111 op = kOpXor;
1112 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001113 default:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001114 LOG(FATAL) << "Unexpected opcode";
Matteo Franchin43ec8732014-03-31 15:00:14 +01001115 }
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001116
1117 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
1118 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
1119 OpRegRegImm(op, rl_result.reg, rl_src1.reg, val);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001120 StoreValueWide(rl_dest, rl_result);
1121}
1122
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001123/**
1124 * @brief Split a register list in pairs or registers.
1125 *
1126 * Given a list of registers in @p reg_mask, split the list in pairs. Use as follows:
1127 * @code
1128 * int reg1 = -1, reg2 = -1;
1129 * while (reg_mask) {
1130 * reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1131 * if (UNLIKELY(reg2 < 0)) {
1132 * // Single register in reg1.
1133 * } else {
1134 * // Pair in reg1, reg2.
1135 * }
1136 * }
1137 * @endcode
1138 */
1139uint32_t Arm64Mir2Lir::GenPairWise(uint32_t reg_mask, int* reg1, int* reg2) {
1140 // Find first register.
1141 int first_bit_set = __builtin_ctz(reg_mask) + 1;
1142 int reg = *reg1 + first_bit_set;
1143 reg_mask >>= first_bit_set;
1144
1145 if (LIKELY(reg_mask)) {
1146 // Save the first register, find the second and use the pair opcode.
1147 int second_bit_set = __builtin_ctz(reg_mask) + 1;
1148 *reg2 = reg;
1149 reg_mask >>= second_bit_set;
1150 *reg1 = reg + second_bit_set;
1151 return reg_mask;
1152 }
1153
1154 // Use the single opcode, as we just have one register.
1155 *reg1 = reg;
1156 *reg2 = -1;
1157 return reg_mask;
1158}
1159
1160void Arm64Mir2Lir::UnSpillCoreRegs(RegStorage base, int offset, uint32_t reg_mask) {
1161 int reg1 = -1, reg2 = -1;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001162 const int reg_log2_size = 3;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001163
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001164 for (offset = (offset >> reg_log2_size); reg_mask; offset += 2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001165 reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1166 if (UNLIKELY(reg2 < 0)) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001167 NewLIR3(WIDE(kA64Ldr3rXD), RegStorage::Solo64(reg1).GetReg(), base.GetReg(), offset);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001168 } else {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001169 NewLIR4(WIDE(kA64Ldp4rrXD), RegStorage::Solo64(reg2).GetReg(),
1170 RegStorage::Solo64(reg1).GetReg(), base.GetReg(), offset);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001171 }
1172 }
1173}
1174
1175void Arm64Mir2Lir::SpillCoreRegs(RegStorage base, int offset, uint32_t reg_mask) {
1176 int reg1 = -1, reg2 = -1;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001177 const int reg_log2_size = 3;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001178
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001179 for (offset = (offset >> reg_log2_size); reg_mask; offset += 2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001180 reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1181 if (UNLIKELY(reg2 < 0)) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001182 NewLIR3(WIDE(kA64Str3rXD), RegStorage::Solo64(reg1).GetReg(), base.GetReg(), offset);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001183 } else {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001184 NewLIR4(WIDE(kA64Stp4rrXD), RegStorage::Solo64(reg2).GetReg(),
1185 RegStorage::Solo64(reg1).GetReg(), base.GetReg(), offset);
1186 }
1187 }
1188}
1189
1190void Arm64Mir2Lir::UnSpillFPRegs(RegStorage base, int offset, uint32_t reg_mask) {
1191 int reg1 = -1, reg2 = -1;
1192 const int reg_log2_size = 3;
1193
1194 for (offset = (offset >> reg_log2_size); reg_mask; offset += 2) {
1195 reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1196 if (UNLIKELY(reg2 < 0)) {
1197 NewLIR3(FWIDE(kA64Ldr3fXD), RegStorage::FloatSolo64(reg1).GetReg(), base.GetReg(), offset);
1198 } else {
1199 NewLIR4(WIDE(kA64Ldp4ffXD), RegStorage::FloatSolo64(reg2).GetReg(),
1200 RegStorage::FloatSolo64(reg1).GetReg(), base.GetReg(), offset);
1201 }
1202 }
1203}
1204
1205// TODO(Arm64): consider using ld1 and st1?
1206void Arm64Mir2Lir::SpillFPRegs(RegStorage base, int offset, uint32_t reg_mask) {
1207 int reg1 = -1, reg2 = -1;
1208 const int reg_log2_size = 3;
1209
1210 for (offset = (offset >> reg_log2_size); reg_mask; offset += 2) {
1211 reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1212 if (UNLIKELY(reg2 < 0)) {
1213 NewLIR3(FWIDE(kA64Str3fXD), RegStorage::FloatSolo64(reg1).GetReg(), base.GetReg(), offset);
1214 } else {
1215 NewLIR4(WIDE(kA64Stp4ffXD), RegStorage::FloatSolo64(reg2).GetReg(),
1216 RegStorage::FloatSolo64(reg1).GetReg(), base.GetReg(), offset);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001217 }
1218 }
1219}
1220
Matteo Franchin43ec8732014-03-31 15:00:14 +01001221} // namespace art