blob: 38f110ead21554ce451b751f1ea19936eb128165 [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) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100728 // TODO(Arm64): re-enable suspend checks, once art_quick_test_suspend is implemented and
729 // the suspend register is properly handled in the trampolines.
730#if 0
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100731 NewLIR3(kA64Subs3rRd, rA64_SUSPEND, rA64_SUSPEND, 1);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100732 return OpCondBranch((target == NULL) ? kCondEq : kCondNe, target);
Matteo Franchinbc6d1972014-05-13 12:33:28 +0100733#else
734 // TODO(Arm64): Fake suspend check. Will always fail to branch. Remove this.
735 LIR* branch = NewLIR2((target == NULL) ? kA64Cbnz2rt : kA64Cbz2rt, rwzr, 0);
736 branch->target = target;
737 return branch;
738#endif
Matteo Franchin43ec8732014-03-31 15:00:14 +0100739}
740
741// Decrement register and branch on condition
742LIR* Arm64Mir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) {
743 // Combine sub & test using sub setflags encoding here
744 OpRegRegImm(kOpSub, reg, reg, 1); // For value == 1, this should set flags.
745 DCHECK(last_lir_insn_->u.m.def_mask & ENCODE_CCODE);
746 return OpCondBranch(c_code, target);
747}
748
Andreas Gampeb14329f2014-05-15 11:16:06 -0700749bool Arm64Mir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100750#if ANDROID_SMP != 0
751 // Start off with using the last LIR as the barrier. If it is not enough, then we will generate one.
752 LIR* barrier = last_lir_insn_;
753
754 int dmb_flavor;
755 // TODO: revisit Arm barrier kinds
756 switch (barrier_kind) {
757 case kLoadStore: dmb_flavor = kISH; break;
758 case kLoadLoad: dmb_flavor = kISH; break;
759 case kStoreStore: dmb_flavor = kISHST; break;
760 case kStoreLoad: dmb_flavor = kISH; break;
761 default:
762 LOG(FATAL) << "Unexpected MemBarrierKind: " << barrier_kind;
763 dmb_flavor = kSY; // quiet gcc.
764 break;
765 }
766
Andreas Gampeb14329f2014-05-15 11:16:06 -0700767 bool ret = false;
768
Matteo Franchin43ec8732014-03-31 15:00:14 +0100769 // If the same barrier already exists, don't generate another.
770 if (barrier == nullptr
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100771 || (barrier->opcode != kA64Dmb1B || barrier->operands[0] != dmb_flavor)) {
772 barrier = NewLIR1(kA64Dmb1B, dmb_flavor);
Andreas Gampeb14329f2014-05-15 11:16:06 -0700773 ret = true;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100774 }
775
776 // At this point we must have a memory barrier. Mark it as a scheduling barrier as well.
777 DCHECK(!barrier->flags.use_def_invalid);
778 barrier->u.m.def_mask = ENCODE_ALL;
Andreas Gampeb14329f2014-05-15 11:16:06 -0700779 return ret;
780#else
781 return false;
Matteo Franchin43ec8732014-03-31 15:00:14 +0100782#endif
783}
784
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100785void Arm64Mir2Lir::GenIntToLong(RegLocation rl_dest, RegLocation rl_src) {
786 RegLocation rl_result;
787
788 rl_src = LoadValue(rl_src, kCoreReg);
789 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
790 NewLIR4(WIDE(kA64Sbfm4rrdd), rl_result.reg.GetReg(), rl_src.reg.GetReg(), 0, 31);
791 StoreValueWide(rl_dest, rl_result);
792}
793
794void Arm64Mir2Lir::GenDivRemLong(Instruction::Code opcode, RegLocation rl_dest,
795 RegLocation rl_src1, RegLocation rl_src2, bool is_div) {
796 RegLocation rl_result;
797 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
798 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
799 GenDivZeroCheck(rl_src2.reg);
800 rl_result = GenDivRem(rl_dest, rl_src1.reg, rl_src2.reg, is_div);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100801 StoreValueWide(rl_dest, rl_result);
802}
803
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100804void Arm64Mir2Lir::GenLongOp(OpKind op, RegLocation rl_dest, RegLocation rl_src1,
805 RegLocation rl_src2) {
806 RegLocation rl_result;
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100807
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100808 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
809 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
810 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100811 OpRegRegRegShift(op, rl_result.reg, rl_src1.reg, rl_src2.reg, ENCODE_NO_SHIFT);
812 StoreValueWide(rl_dest, rl_result);
813}
814
815void Arm64Mir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
816 RegLocation rl_result;
817
818 rl_src = LoadValueWide(rl_src, kCoreReg);
819 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
820 OpRegRegShift(kOpNeg, rl_result.reg, rl_src.reg, ENCODE_NO_SHIFT);
821 StoreValueWide(rl_dest, rl_result);
822}
823
824void Arm64Mir2Lir::GenNotLong(RegLocation rl_dest, RegLocation rl_src) {
825 RegLocation rl_result;
826
827 rl_src = LoadValueWide(rl_src, kCoreReg);
828 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
829 OpRegRegShift(kOpMvn, rl_result.reg, rl_src.reg, ENCODE_NO_SHIFT);
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100830 StoreValueWide(rl_dest, rl_result);
831}
832
Matteo Franchin43ec8732014-03-31 15:00:14 +0100833void Arm64Mir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest,
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100834 RegLocation rl_src1, RegLocation rl_src2) {
835 GenLongOp(kOpMul, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100836}
837
838void Arm64Mir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100839 RegLocation rl_src2) {
840 GenLongOp(kOpAdd, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100841}
842
843void Arm64Mir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
844 RegLocation rl_src2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100845 GenLongOp(kOpSub, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100846}
847
848void Arm64Mir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
849 RegLocation rl_src2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100850 GenLongOp(kOpAnd, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100851}
852
853void Arm64Mir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
854 RegLocation rl_src2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100855 GenLongOp(kOpOr, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100856}
857
858void Arm64Mir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
859 RegLocation rl_src2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100860 GenLongOp(kOpXor, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +0100861}
862
863/*
864 * Generate array load
865 */
866void Arm64Mir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
867 RegLocation rl_index, RegLocation rl_dest, int scale) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100868 // TODO(Arm64): check this.
869 UNIMPLEMENTED(WARNING);
870
Matteo Franchin43ec8732014-03-31 15:00:14 +0100871 RegisterClass reg_class = RegClassBySize(size);
872 int len_offset = mirror::Array::LengthOffset().Int32Value();
873 int data_offset;
874 RegLocation rl_result;
875 bool constant_index = rl_index.is_const;
876 rl_array = LoadValue(rl_array, kCoreReg);
877 if (!constant_index) {
878 rl_index = LoadValue(rl_index, kCoreReg);
879 }
880
881 if (rl_dest.wide) {
882 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
883 } else {
884 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
885 }
886
887 // If index is constant, just fold it into the data offset
888 if (constant_index) {
889 data_offset += mir_graph_->ConstantValue(rl_index) << scale;
890 }
891
892 /* null object? */
893 GenNullCheck(rl_array.reg, opt_flags);
894
895 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
896 RegStorage reg_len;
897 if (needs_range_check) {
898 reg_len = AllocTemp();
899 /* Get len */
900 Load32Disp(rl_array.reg, len_offset, reg_len);
901 MarkPossibleNullPointerException(opt_flags);
902 } else {
903 ForceImplicitNullCheck(rl_array.reg, opt_flags);
904 }
905 if (rl_dest.wide || rl_dest.fp || constant_index) {
906 RegStorage reg_ptr;
907 if (constant_index) {
908 reg_ptr = rl_array.reg; // NOTE: must not alter reg_ptr in constant case.
909 } else {
910 // No special indexed operation, lea + load w/ displacement
911 reg_ptr = AllocTemp();
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100912 OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.reg, rl_index.reg, EncodeShift(kA64Lsl, scale));
Matteo Franchin43ec8732014-03-31 15:00:14 +0100913 FreeTemp(rl_index.reg);
914 }
915 rl_result = EvalLoc(rl_dest, reg_class, true);
916
917 if (needs_range_check) {
918 if (constant_index) {
919 GenArrayBoundsCheck(mir_graph_->ConstantValue(rl_index), reg_len);
920 } else {
921 GenArrayBoundsCheck(rl_index.reg, reg_len);
922 }
923 FreeTemp(reg_len);
924 }
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100925 LoadBaseDisp(reg_ptr, data_offset, rl_result.reg, size);
Vladimir Marko455759b2014-05-06 20:49:36 +0100926 MarkPossibleNullPointerException(opt_flags);
927 if (!constant_index) {
928 FreeTemp(reg_ptr);
929 }
Matteo Franchin43ec8732014-03-31 15:00:14 +0100930 if (rl_dest.wide) {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100931 StoreValueWide(rl_dest, rl_result);
932 } else {
Matteo Franchin43ec8732014-03-31 15:00:14 +0100933 StoreValue(rl_dest, rl_result);
934 }
935 } else {
936 // Offset base, then use indexed load
937 RegStorage reg_ptr = AllocTemp();
938 OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
939 FreeTemp(rl_array.reg);
940 rl_result = EvalLoc(rl_dest, reg_class, true);
941
942 if (needs_range_check) {
943 GenArrayBoundsCheck(rl_index.reg, reg_len);
944 FreeTemp(reg_len);
945 }
946 LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
947 MarkPossibleNullPointerException(opt_flags);
948 FreeTemp(reg_ptr);
949 StoreValue(rl_dest, rl_result);
950 }
951}
952
953/*
954 * Generate array store
955 *
956 */
957void Arm64Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
958 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +0100959 // TODO(Arm64): check this.
960 UNIMPLEMENTED(WARNING);
961
Matteo Franchin43ec8732014-03-31 15:00:14 +0100962 RegisterClass reg_class = RegClassBySize(size);
963 int len_offset = mirror::Array::LengthOffset().Int32Value();
964 bool constant_index = rl_index.is_const;
965
966 int data_offset;
967 if (size == k64 || size == kDouble) {
968 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
969 } else {
970 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
971 }
972
973 // If index is constant, just fold it into the data offset.
974 if (constant_index) {
975 data_offset += mir_graph_->ConstantValue(rl_index) << scale;
976 }
977
978 rl_array = LoadValue(rl_array, kCoreReg);
979 if (!constant_index) {
980 rl_index = LoadValue(rl_index, kCoreReg);
981 }
982
983 RegStorage reg_ptr;
984 bool allocated_reg_ptr_temp = false;
985 if (constant_index) {
986 reg_ptr = rl_array.reg;
987 } else if (IsTemp(rl_array.reg) && !card_mark) {
988 Clobber(rl_array.reg);
989 reg_ptr = rl_array.reg;
990 } else {
991 allocated_reg_ptr_temp = true;
992 reg_ptr = AllocTemp();
993 }
994
995 /* null object? */
996 GenNullCheck(rl_array.reg, opt_flags);
997
998 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
999 RegStorage reg_len;
1000 if (needs_range_check) {
1001 reg_len = AllocTemp();
1002 // NOTE: max live temps(4) here.
1003 /* Get len */
1004 Load32Disp(rl_array.reg, len_offset, reg_len);
1005 MarkPossibleNullPointerException(opt_flags);
1006 } else {
1007 ForceImplicitNullCheck(rl_array.reg, opt_flags);
1008 }
1009 /* at this point, reg_ptr points to array, 2 live temps */
1010 if (rl_src.wide || rl_src.fp || constant_index) {
1011 if (rl_src.wide) {
1012 rl_src = LoadValueWide(rl_src, reg_class);
1013 } else {
1014 rl_src = LoadValue(rl_src, reg_class);
1015 }
1016 if (!constant_index) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001017 OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.reg, rl_index.reg, EncodeShift(kA64Lsl, scale));
Matteo Franchin43ec8732014-03-31 15:00:14 +01001018 }
1019 if (needs_range_check) {
1020 if (constant_index) {
1021 GenArrayBoundsCheck(mir_graph_->ConstantValue(rl_index), reg_len);
1022 } else {
1023 GenArrayBoundsCheck(rl_index.reg, reg_len);
1024 }
1025 FreeTemp(reg_len);
1026 }
1027
Vladimir Marko455759b2014-05-06 20:49:36 +01001028 StoreBaseDisp(reg_ptr, data_offset, rl_src.reg, size);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001029 MarkPossibleNullPointerException(opt_flags);
1030 } else {
1031 /* reg_ptr -> array data */
1032 OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
1033 rl_src = LoadValue(rl_src, reg_class);
1034 if (needs_range_check) {
1035 GenArrayBoundsCheck(rl_index.reg, reg_len);
1036 FreeTemp(reg_len);
1037 }
1038 StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
1039 MarkPossibleNullPointerException(opt_flags);
1040 }
1041 if (allocated_reg_ptr_temp) {
1042 FreeTemp(reg_ptr);
1043 }
1044 if (card_mark) {
1045 MarkGCCard(rl_src.reg, rl_array.reg);
1046 }
1047}
1048
Matteo Franchin43ec8732014-03-31 15:00:14 +01001049void Arm64Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode,
1050 RegLocation rl_dest, RegLocation rl_src, RegLocation rl_shift) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001051 OpKind op = kOpBkpt;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001052 // Per spec, we only care about low 6 bits of shift amount.
1053 int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f;
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001054 rl_src = LoadValueWide(rl_src, kCoreReg);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001055 if (shift_amount == 0) {
1056 StoreValueWide(rl_dest, rl_src);
1057 return;
1058 }
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001059
1060 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001061 switch (opcode) {
1062 case Instruction::SHL_LONG:
1063 case Instruction::SHL_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001064 op = kOpLsl;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001065 break;
1066 case Instruction::SHR_LONG:
1067 case Instruction::SHR_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001068 op = kOpAsr;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001069 break;
1070 case Instruction::USHR_LONG:
1071 case Instruction::USHR_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001072 op = kOpLsr;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001073 break;
1074 default:
1075 LOG(FATAL) << "Unexpected case";
1076 }
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001077 OpRegRegImm(op, rl_result.reg, rl_src.reg, shift_amount);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001078 StoreValueWide(rl_dest, rl_result);
1079}
1080
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001081void Arm64Mir2Lir::GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
1082 RegLocation rl_src1, RegLocation rl_src2) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001083 if ((opcode == Instruction::SUB_LONG) || (opcode == Instruction::SUB_LONG_2ADDR)) {
Matteo Franchin43ec8732014-03-31 15:00:14 +01001084 if (!rl_src2.is_const) {
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001085 return GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001086 }
1087 } else {
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001088 // Associativity.
Matteo Franchin43ec8732014-03-31 15:00:14 +01001089 if (!rl_src2.is_const) {
1090 DCHECK(rl_src1.is_const);
1091 std::swap(rl_src1, rl_src2);
1092 }
1093 }
Matteo Franchin43ec8732014-03-31 15:00:14 +01001094 DCHECK(rl_src2.is_const);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001095
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001096 OpKind op = kOpBkpt;
1097 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
1098
Matteo Franchin43ec8732014-03-31 15:00:14 +01001099 switch (opcode) {
1100 case Instruction::ADD_LONG:
1101 case Instruction::ADD_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001102 op = kOpAdd;
1103 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001104 case Instruction::SUB_LONG:
1105 case Instruction::SUB_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001106 op = kOpSub;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001107 break;
1108 case Instruction::AND_LONG:
1109 case Instruction::AND_LONG_2ADDR:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001110 op = kOpAnd;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001111 break;
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001112 case Instruction::OR_LONG:
1113 case Instruction::OR_LONG_2ADDR:
1114 op = kOpOr;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001115 break;
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001116 case Instruction::XOR_LONG:
1117 case Instruction::XOR_LONG_2ADDR:
1118 op = kOpXor;
1119 break;
Matteo Franchin43ec8732014-03-31 15:00:14 +01001120 default:
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001121 LOG(FATAL) << "Unexpected opcode";
Matteo Franchin43ec8732014-03-31 15:00:14 +01001122 }
Serban Constantinescued65c5e2014-05-22 15:10:18 +01001123
1124 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
1125 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
1126 OpRegRegImm(op, rl_result.reg, rl_src1.reg, val);
Matteo Franchin43ec8732014-03-31 15:00:14 +01001127 StoreValueWide(rl_dest, rl_result);
1128}
1129
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001130/**
1131 * @brief Split a register list in pairs or registers.
1132 *
1133 * Given a list of registers in @p reg_mask, split the list in pairs. Use as follows:
1134 * @code
1135 * int reg1 = -1, reg2 = -1;
1136 * while (reg_mask) {
1137 * reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1138 * if (UNLIKELY(reg2 < 0)) {
1139 * // Single register in reg1.
1140 * } else {
1141 * // Pair in reg1, reg2.
1142 * }
1143 * }
1144 * @endcode
1145 */
1146uint32_t Arm64Mir2Lir::GenPairWise(uint32_t reg_mask, int* reg1, int* reg2) {
1147 // Find first register.
1148 int first_bit_set = __builtin_ctz(reg_mask) + 1;
1149 int reg = *reg1 + first_bit_set;
1150 reg_mask >>= first_bit_set;
1151
1152 if (LIKELY(reg_mask)) {
1153 // Save the first register, find the second and use the pair opcode.
1154 int second_bit_set = __builtin_ctz(reg_mask) + 1;
1155 *reg2 = reg;
1156 reg_mask >>= second_bit_set;
1157 *reg1 = reg + second_bit_set;
1158 return reg_mask;
1159 }
1160
1161 // Use the single opcode, as we just have one register.
1162 *reg1 = reg;
1163 *reg2 = -1;
1164 return reg_mask;
1165}
1166
1167void Arm64Mir2Lir::UnSpillCoreRegs(RegStorage base, int offset, uint32_t reg_mask) {
1168 int reg1 = -1, reg2 = -1;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001169 const int reg_log2_size = 3;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001170
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001171 for (offset = (offset >> reg_log2_size); reg_mask; offset += 2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001172 reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1173 if (UNLIKELY(reg2 < 0)) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001174 NewLIR3(WIDE(kA64Ldr3rXD), RegStorage::Solo64(reg1).GetReg(), base.GetReg(), offset);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001175 } else {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001176 NewLIR4(WIDE(kA64Ldp4rrXD), RegStorage::Solo64(reg2).GetReg(),
1177 RegStorage::Solo64(reg1).GetReg(), base.GetReg(), offset);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001178 }
1179 }
1180}
1181
1182void Arm64Mir2Lir::SpillCoreRegs(RegStorage base, int offset, uint32_t reg_mask) {
1183 int reg1 = -1, reg2 = -1;
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001184 const int reg_log2_size = 3;
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001185
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001186 for (offset = (offset >> reg_log2_size); reg_mask; offset += 2) {
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001187 reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1188 if (UNLIKELY(reg2 < 0)) {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001189 NewLIR3(WIDE(kA64Str3rXD), RegStorage::Solo64(reg1).GetReg(), base.GetReg(), offset);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001190 } else {
Matteo Franchinbc6d1972014-05-13 12:33:28 +01001191 NewLIR4(WIDE(kA64Stp4rrXD), RegStorage::Solo64(reg2).GetReg(),
1192 RegStorage::Solo64(reg1).GetReg(), base.GetReg(), offset);
1193 }
1194 }
1195}
1196
1197void Arm64Mir2Lir::UnSpillFPRegs(RegStorage base, int offset, uint32_t reg_mask) {
1198 int reg1 = -1, reg2 = -1;
1199 const int reg_log2_size = 3;
1200
1201 for (offset = (offset >> reg_log2_size); reg_mask; offset += 2) {
1202 reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1203 if (UNLIKELY(reg2 < 0)) {
1204 NewLIR3(FWIDE(kA64Ldr3fXD), RegStorage::FloatSolo64(reg1).GetReg(), base.GetReg(), offset);
1205 } else {
1206 NewLIR4(WIDE(kA64Ldp4ffXD), RegStorage::FloatSolo64(reg2).GetReg(),
1207 RegStorage::FloatSolo64(reg1).GetReg(), base.GetReg(), offset);
1208 }
1209 }
1210}
1211
1212// TODO(Arm64): consider using ld1 and st1?
1213void Arm64Mir2Lir::SpillFPRegs(RegStorage base, int offset, uint32_t reg_mask) {
1214 int reg1 = -1, reg2 = -1;
1215 const int reg_log2_size = 3;
1216
1217 for (offset = (offset >> reg_log2_size); reg_mask; offset += 2) {
1218 reg_mask = GenPairWise(reg_mask, & reg1, & reg2);
1219 if (UNLIKELY(reg2 < 0)) {
1220 NewLIR3(FWIDE(kA64Str3fXD), RegStorage::FloatSolo64(reg1).GetReg(), base.GetReg(), offset);
1221 } else {
1222 NewLIR4(WIDE(kA64Stp4ffXD), RegStorage::FloatSolo64(reg2).GetReg(),
1223 RegStorage::FloatSolo64(reg1).GetReg(), base.GetReg(), offset);
Matteo Franchine45fb9e2014-05-06 10:10:30 +01001224 }
1225 }
1226}
1227
Matteo Franchin43ec8732014-03-31 15:00:14 +01001228} // namespace art