ralloc_util.cc revision 091cc408e9dc87e60fb64c61e186bea568fc3d3a
1/*
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 register alloction support. */
18
19#include "dex/compiler_ir.h"
20#include "dex/compiler_internals.h"
21#include "mir_to_lir-inl.h"
22
23namespace art {
24
25/*
26 * Free all allocated temps in the temp pools.  Note that this does
27 * not affect the "liveness" of a temp register, which will stay
28 * live until it is either explicitly killed or reallocated.
29 */
30void Mir2Lir::ResetRegPool() {
31  GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
32  for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) {
33    info->MarkFree();
34  }
35  // Reset temp tracking sanity check.
36  if (kIsDebugBuild) {
37    live_sreg_ = INVALID_SREG;
38  }
39}
40
41Mir2Lir::RegisterInfo::RegisterInfo(RegStorage r, uint64_t mask)
42  : reg_(r), is_temp_(false), wide_value_(false), live_(false),
43    dirty_(false), partner_(r), s_reg_(INVALID_SREG), def_use_mask_(mask), master_(this) {
44  switch (r.StorageSize()) {
45    case 0: storage_mask_ = 0xffffffff; break;
46    case 4: storage_mask_ = 0x00000001; break;
47    case 8: storage_mask_ = 0x00000003; break;
48    case 16: storage_mask_ = 0x0000000f; break;
49    case 32: storage_mask_ = 0x000000ff; break;
50    case 64: storage_mask_ = 0x0000ffff; break;
51    case 128: storage_mask_ = 0xffffffff; break;
52  }
53  used_storage_ = r.Valid() ? ~storage_mask_ : storage_mask_;
54}
55
56Mir2Lir::RegisterPool::RegisterPool(Mir2Lir* m2l, ArenaAllocator* arena,
57                                    const std::vector<RegStorage>& core_regs,
58                                    const std::vector<RegStorage>& sp_regs,
59                                    const std::vector<RegStorage>& dp_regs,
60                                    const std::vector<RegStorage>& reserved_regs,
61                                    const std::vector<RegStorage>& core_temps,
62                                    const std::vector<RegStorage>& sp_temps,
63                                    const std::vector<RegStorage>& dp_temps) :
64    core_regs_(arena, core_regs.size()), next_core_reg_(0), sp_regs_(arena, sp_regs.size()),
65    next_sp_reg_(0), dp_regs_(arena, dp_regs.size()), next_dp_reg_(0), m2l_(m2l)  {
66  // Initialize the fast lookup map.
67  m2l_->reginfo_map_.Reset();
68  m2l_->reginfo_map_.Resize(RegStorage::kMaxRegs);
69  for (unsigned i = 0; i < RegStorage::kMaxRegs; i++) {
70    m2l_->reginfo_map_.Insert(nullptr);
71  }
72
73  // Construct the register pool.
74  for (RegStorage reg : core_regs) {
75    RegisterInfo* info = new (arena) RegisterInfo(reg, m2l_->GetRegMaskCommon(reg));
76    m2l_->reginfo_map_.Put(reg.GetReg(), info);
77    core_regs_.Insert(info);
78  }
79  for (RegStorage reg : sp_regs) {
80    RegisterInfo* info = new (arena) RegisterInfo(reg, m2l_->GetRegMaskCommon(reg));
81    m2l_->reginfo_map_.Put(reg.GetReg(), info);
82    sp_regs_.Insert(info);
83  }
84  for (RegStorage reg : dp_regs) {
85    RegisterInfo* info = new (arena) RegisterInfo(reg, m2l_->GetRegMaskCommon(reg));
86    m2l_->reginfo_map_.Put(reg.GetReg(), info);
87    dp_regs_.Insert(info);
88  }
89
90  // Keep special registers from being allocated.
91  for (RegStorage reg : reserved_regs) {
92    m2l_->MarkInUse(reg);
93  }
94
95  // Mark temp regs - all others not in use can be used for promotion
96  for (RegStorage reg : core_temps) {
97    m2l_->MarkTemp(reg);
98  }
99  for (RegStorage reg : sp_temps) {
100    m2l_->MarkTemp(reg);
101  }
102  for (RegStorage reg : dp_temps) {
103    m2l_->MarkTemp(reg);
104  }
105
106  // Add an entry for InvalidReg with zero'd mask.
107  RegisterInfo* invalid_reg = new (arena) RegisterInfo(RegStorage::InvalidReg(), 0);
108  m2l_->reginfo_map_.Put(RegStorage::InvalidReg().GetReg(), invalid_reg);
109}
110
111void Mir2Lir::DumpRegPool(GrowableArray<RegisterInfo*>* regs) {
112  LOG(INFO) << "================================================";
113  GrowableArray<RegisterInfo*>::Iterator it(regs);
114  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
115    LOG(INFO) << StringPrintf(
116        "R[%d:%d:%c]: T:%d, U:%d, W:%d, p:%d, LV:%d, D:%d, SR:%d, DEF:%d",
117        info->GetReg().GetReg(), info->GetReg().GetRegNum(), info->GetReg().IsFloat() ?  'f' : 'c',
118        info->IsTemp(), info->InUse(), info->IsWide(), info->Partner().GetReg(), info->IsLive(),
119        info->IsDirty(), info->SReg(), info->DefStart() != nullptr);
120  }
121  LOG(INFO) << "================================================";
122}
123
124void Mir2Lir::DumpCoreRegPool() {
125  DumpRegPool(&reg_pool_->core_regs_);
126}
127
128void Mir2Lir::DumpFpRegPool() {
129  DumpRegPool(&reg_pool_->sp_regs_);
130  DumpRegPool(&reg_pool_->dp_regs_);
131}
132
133void Mir2Lir::DumpRegPools() {
134  LOG(INFO) << "Core registers";
135  DumpCoreRegPool();
136  LOG(INFO) << "FP registers";
137  DumpFpRegPool();
138}
139
140void Mir2Lir::Clobber(RegStorage reg) {
141  if (reg.IsPair()) {
142    ClobberBody(GetRegInfo(reg.GetLow()));
143    ClobberBody(GetRegInfo(reg.GetHigh()));
144  } else {
145    ClobberBody(GetRegInfo(reg));
146  }
147}
148
149void Mir2Lir::ClobberSRegBody(GrowableArray<RegisterInfo*>* regs, int s_reg) {
150  GrowableArray<RegisterInfo*>::Iterator it(regs);
151  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
152    if ((info->SReg() == s_reg)  ||
153        (info->IsWide() && (GetRegInfo(info->Partner())->SReg() == s_reg))) {
154      // NOTE: a single s_reg may appear multiple times, so we can't short-circuit.
155      if (info->IsTemp()) {
156        info->SetIsLive(false);
157      }
158      info->ResetDefBody();
159    }
160  }
161}
162
163/*
164 * Break the association between a Dalvik vreg and a physical temp register of either register
165 * class.
166 * TODO: Ideally, the public version of this code should not exist.  Besides its local usage
167 * in the register utilities, is is also used by code gen routines to work around a deficiency in
168 * local register allocation, which fails to distinguish between the "in" and "out" identities
169 * of Dalvik vregs.  This can result in useless register copies when the same Dalvik vreg
170 * is used both as the source and destination register of an operation in which the type
171 * changes (for example: INT_TO_FLOAT v1, v1).  Revisit when improved register allocation is
172 * addressed.
173 */
174void Mir2Lir::ClobberSReg(int s_reg) {
175  if (s_reg != INVALID_SREG) {
176    /* Reset live temp tracking sanity checker */
177    if (kIsDebugBuild) {
178      if (s_reg == live_sreg_) {
179        live_sreg_ = INVALID_SREG;
180      }
181    }
182    ClobberSRegBody(&reg_pool_->core_regs_, s_reg);
183    ClobberSRegBody(&reg_pool_->sp_regs_, s_reg);
184    ClobberSRegBody(&reg_pool_->dp_regs_, s_reg);
185  }
186}
187
188/*
189 * SSA names associated with the initial definitions of Dalvik
190 * registers are the same as the Dalvik register number (and
191 * thus take the same position in the promotion_map.  However,
192 * the special Method* and compiler temp resisters use negative
193 * v_reg numbers to distinguish them and can have an arbitrary
194 * ssa name (above the last original Dalvik register).  This function
195 * maps SSA names to positions in the promotion_map array.
196 */
197int Mir2Lir::SRegToPMap(int s_reg) {
198  DCHECK_LT(s_reg, mir_graph_->GetNumSSARegs());
199  DCHECK_GE(s_reg, 0);
200  int v_reg = mir_graph_->SRegToVReg(s_reg);
201  if (v_reg >= 0) {
202    DCHECK_LT(v_reg, cu_->num_dalvik_registers);
203    return v_reg;
204  } else {
205    /*
206     * It must be the case that the v_reg for temporary is less than or equal to the
207     * base reg for temps. For that reason, "position" must be zero or positive.
208     */
209    unsigned int position = std::abs(v_reg) - std::abs(static_cast<int>(kVRegTempBaseReg));
210
211    // The temporaries are placed after dalvik registers in the promotion map
212    DCHECK_LT(position, mir_graph_->GetNumUsedCompilerTemps());
213    return cu_->num_dalvik_registers + position;
214  }
215}
216
217// TODO: refactor following Alloc/Record routines - much commonality.
218void Mir2Lir::RecordCorePromotion(RegStorage reg, int s_reg) {
219  int p_map_idx = SRegToPMap(s_reg);
220  int v_reg = mir_graph_->SRegToVReg(s_reg);
221  int reg_num = reg.GetRegNum();
222  GetRegInfo(reg)->MarkInUse();
223  core_spill_mask_ |= (1 << reg_num);
224  // Include reg for later sort
225  core_vmap_table_.push_back(reg_num << VREG_NUM_WIDTH | (v_reg & ((1 << VREG_NUM_WIDTH) - 1)));
226  num_core_spills_++;
227  promotion_map_[p_map_idx].core_location = kLocPhysReg;
228  promotion_map_[p_map_idx].core_reg = reg_num;
229}
230
231/* Reserve a callee-save register.  Return InvalidReg if none available */
232RegStorage Mir2Lir::AllocPreservedCoreReg(int s_reg) {
233  RegStorage res;
234  GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->core_regs_);
235  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
236    if (!info->IsTemp() && !info->InUse()) {
237      res = info->GetReg();
238      RecordCorePromotion(res, s_reg);
239      break;
240    }
241  }
242  return res;
243}
244
245void Mir2Lir::RecordSinglePromotion(RegStorage reg, int s_reg) {
246  int p_map_idx = SRegToPMap(s_reg);
247  int v_reg = mir_graph_->SRegToVReg(s_reg);
248  GetRegInfo(reg)->MarkInUse();
249  MarkPreservedSingle(v_reg, reg);
250  promotion_map_[p_map_idx].fp_location = kLocPhysReg;
251  promotion_map_[p_map_idx].FpReg = reg.GetReg();
252}
253
254// Reserve a callee-save sp single register.
255RegStorage Mir2Lir::AllocPreservedSingle(int s_reg) {
256  RegStorage res;
257  GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
258  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
259    if (!info->IsTemp() && !info->InUse()) {
260      res = info->GetReg();
261      RecordSinglePromotion(res, s_reg);
262      break;
263    }
264  }
265  return res;
266}
267
268void Mir2Lir::RecordDoublePromotion(RegStorage reg, int s_reg) {
269  int p_map_idx = SRegToPMap(s_reg);
270  int v_reg = mir_graph_->SRegToVReg(s_reg);
271  GetRegInfo(reg)->MarkInUse();
272  MarkPreservedDouble(v_reg, reg);
273  promotion_map_[p_map_idx].fp_location = kLocPhysReg;
274  promotion_map_[p_map_idx].FpReg = reg.GetReg();
275}
276
277// Reserve a callee-save dp solo register.
278RegStorage Mir2Lir::AllocPreservedDouble(int s_reg) {
279  RegStorage res;
280  GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->dp_regs_);
281  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
282    if (!info->IsTemp() && !info->InUse()) {
283      res = info->GetReg();
284      RecordDoublePromotion(res, s_reg);
285      break;
286    }
287  }
288  return res;
289}
290
291
292RegStorage Mir2Lir::AllocTempBody(GrowableArray<RegisterInfo*> &regs, int* next_temp, bool required) {
293  int num_regs = regs.Size();
294  int next = *next_temp;
295  for (int i = 0; i< num_regs; i++) {
296    if (next >= num_regs)
297      next = 0;
298    RegisterInfo* info = regs.Get(next);
299    if (info->IsTemp() && !info->InUse() && !info->IsLive()) {
300      Clobber(info->GetReg());
301      info->MarkInUse();
302      info->SetIsWide(false);
303      *next_temp = next + 1;
304      return info->GetReg();
305    }
306    next++;
307  }
308  next = *next_temp;
309  for (int i = 0; i< num_regs; i++) {
310    if (next >= num_regs)
311      next = 0;
312    RegisterInfo* info = regs.Get(next);
313    if (info->IsTemp() && !info->InUse()) {
314      Clobber(info->GetReg());
315      info->MarkInUse();
316      info->SetIsWide(false);
317      *next_temp = next + 1;
318      return info->GetReg();
319    }
320    next++;
321  }
322  if (required) {
323    CodegenDump();
324    DumpRegPools();
325    LOG(FATAL) << "No free temp registers";
326  }
327  return RegStorage::InvalidReg();  // No register available
328}
329
330/* Return a temp if one is available, -1 otherwise */
331RegStorage Mir2Lir::AllocFreeTemp() {
332  return AllocTempBody(reg_pool_->core_regs_, &reg_pool_->next_core_reg_, false);
333}
334
335RegStorage Mir2Lir::AllocTemp() {
336  return AllocTempBody(reg_pool_->core_regs_, &reg_pool_->next_core_reg_, true);
337}
338
339RegStorage Mir2Lir::AllocTempSingle() {
340  RegStorage res = AllocTempBody(reg_pool_->sp_regs_, &reg_pool_->next_sp_reg_, true);
341  DCHECK(res.IsSingle()) << "Reg: 0x" << std::hex << res.GetRawBits();
342  return res;
343}
344
345RegStorage Mir2Lir::AllocTempDouble() {
346  RegStorage res = AllocTempBody(reg_pool_->dp_regs_, &reg_pool_->next_dp_reg_, true);
347  DCHECK(res.IsDouble()) << "Reg: 0x" << std::hex << res.GetRawBits();
348  return res;
349}
350
351RegStorage Mir2Lir::FindLiveReg(GrowableArray<RegisterInfo*> &regs, int s_reg) {
352  RegStorage res;
353  GrowableArray<RegisterInfo*>::Iterator it(&regs);
354  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
355    if ((info->SReg() == s_reg) && info->IsLive()) {
356      res = info->GetReg();
357      break;
358    }
359  }
360  return res;
361}
362
363RegStorage Mir2Lir::AllocLiveReg(int s_reg, int reg_class, bool wide) {
364  RegStorage reg;
365  // TODO: might be worth a sanity check here to verify at most 1 live reg per s_reg.
366  if ((reg_class == kAnyReg) || (reg_class == kFPReg)) {
367    reg = FindLiveReg(wide ? reg_pool_->dp_regs_ : reg_pool_->sp_regs_, s_reg);
368  }
369  if (!reg.Valid() && (reg_class != kFPReg)) {
370    reg = FindLiveReg(reg_pool_->core_regs_, s_reg);
371  }
372  if (reg.Valid()) {
373    if (wide && reg.Is32Bit() && !reg.IsFloat()) {
374      // Only allow reg pairs for Core.
375      RegStorage high_reg = FindLiveReg(reg_pool_->core_regs_, s_reg + 1);
376      if (high_reg.Valid()) {
377        RegisterInfo* info_lo = GetRegInfo(reg);
378        RegisterInfo* info_hi = GetRegInfo(high_reg);
379        if (info_lo->IsTemp()) {
380          info_lo->MarkInUse();
381        }
382        if (info_hi->IsTemp()) {
383          info_hi->MarkInUse();
384        }
385        reg = RegStorage::MakeRegPair(reg, high_reg);
386        MarkWide(reg);
387      } else {
388        // Only half available - clobber.
389        Clobber(reg);
390        reg = RegStorage::InvalidReg();
391      }
392    }
393    if (reg.Valid() && !reg.IsPair()) {
394      RegisterInfo* info = GetRegInfo(reg);
395      if (info->IsTemp()) {
396        info->MarkInUse();
397      }
398    }
399    if (reg.Valid() && (wide != GetRegInfo(reg)->IsWide())) {
400      // Width mismatch - don't try to reuse.
401      Clobber(reg);
402      reg = RegStorage::InvalidReg();
403    }
404  }
405  return reg;
406}
407
408void Mir2Lir::FreeTemp(RegStorage reg) {
409  if (reg.IsPair()) {
410    FreeTemp(reg.GetLow());
411    FreeTemp(reg.GetHigh());
412  } else {
413    RegisterInfo* p = GetRegInfo(reg);
414    if (p->IsTemp()) {
415      p->MarkFree();
416      p->SetIsWide(false);
417      p->SetPartner(reg);
418    }
419  }
420}
421
422bool Mir2Lir::IsLive(RegStorage reg) {
423  bool res;
424  if (reg.IsPair()) {
425    RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
426    RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
427    res = p_lo->IsLive() || p_hi->IsLive();
428  } else {
429    RegisterInfo* p = GetRegInfo(reg);
430    res = p->IsLive();
431  }
432  return res;
433}
434
435bool Mir2Lir::IsTemp(RegStorage reg) {
436  bool res;
437  if (reg.IsPair()) {
438    RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
439    RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
440    res = p_lo->IsTemp() || p_hi->IsTemp();
441  } else {
442    RegisterInfo* p = GetRegInfo(reg);
443    res = p->IsTemp();
444  }
445  return res;
446}
447
448bool Mir2Lir::IsPromoted(RegStorage reg) {
449  bool res;
450  if (reg.IsPair()) {
451    RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
452    RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
453    res = !p_lo->IsTemp() || !p_hi->IsTemp();
454  } else {
455    RegisterInfo* p = GetRegInfo(reg);
456    res = !p->IsTemp();
457  }
458  return res;
459}
460
461bool Mir2Lir::IsDirty(RegStorage reg) {
462  bool res;
463  if (reg.IsPair()) {
464    RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
465    RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
466    res = p_lo->IsDirty() || p_hi->IsDirty();
467  } else {
468    RegisterInfo* p = GetRegInfo(reg);
469    res = p->IsDirty();
470  }
471  return res;
472}
473
474/*
475 * Similar to AllocTemp(), but forces the allocation of a specific
476 * register.  No check is made to see if the register was previously
477 * allocated.  Use with caution.
478 */
479void Mir2Lir::LockTemp(RegStorage reg) {
480  DCHECK(IsTemp(reg));
481  if (reg.IsPair()) {
482    RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
483    RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
484    p_lo->MarkInUse();
485    p_lo->SetIsLive(false);
486    p_hi->MarkInUse();
487    p_hi->SetIsLive(false);
488  } else {
489    RegisterInfo* p = GetRegInfo(reg);
490    p->MarkInUse();
491    p->SetIsLive(false);
492  }
493}
494
495void Mir2Lir::ResetDef(RegStorage reg) {
496  if (reg.IsPair()) {
497    GetRegInfo(reg.GetLow())->ResetDefBody();
498    GetRegInfo(reg.GetHigh())->ResetDefBody();
499  } else {
500    GetRegInfo(reg)->ResetDefBody();
501  }
502}
503
504void Mir2Lir::NullifyRange(RegStorage reg, int s_reg) {
505  RegisterInfo* info = nullptr;
506  RegStorage rs = reg.IsPair() ? reg.GetLow() : reg;
507  if (IsTemp(rs)) {
508    info = GetRegInfo(reg);
509  }
510  if ((info != nullptr) && (info->DefStart() != nullptr) && (info->DefEnd() != nullptr)) {
511    DCHECK_EQ(info->SReg(), s_reg);  // Make sure we're on the same page.
512    for (LIR* p = info->DefStart();; p = p->next) {
513      NopLIR(p);
514      if (p == info->DefEnd()) {
515        break;
516      }
517    }
518  }
519}
520
521/*
522 * Mark the beginning and end LIR of a def sequence.  Note that
523 * on entry start points to the LIR prior to the beginning of the
524 * sequence.
525 */
526void Mir2Lir::MarkDef(RegLocation rl, LIR *start, LIR *finish) {
527  DCHECK(!rl.wide);
528  DCHECK(start && start->next);
529  DCHECK(finish);
530  RegisterInfo* p = GetRegInfo(rl.reg);
531  p->SetDefStart(start->next);
532  p->SetDefEnd(finish);
533}
534
535/*
536 * Mark the beginning and end LIR of a def sequence.  Note that
537 * on entry start points to the LIR prior to the beginning of the
538 * sequence.
539 */
540void Mir2Lir::MarkDefWide(RegLocation rl, LIR *start, LIR *finish) {
541  DCHECK(rl.wide);
542  DCHECK(start && start->next);
543  DCHECK(finish);
544  RegisterInfo* p;
545  if (rl.reg.IsPair()) {
546    p = GetRegInfo(rl.reg.GetLow());
547    ResetDef(rl.reg.GetHigh());  // Only track low of pair
548  } else {
549    p = GetRegInfo(rl.reg);
550  }
551  p->SetDefStart(start->next);
552  p->SetDefEnd(finish);
553}
554
555RegLocation Mir2Lir::WideToNarrow(RegLocation rl) {
556  DCHECK(rl.wide);
557  if (rl.location == kLocPhysReg) {
558    if (rl.reg.IsPair()) {
559      RegisterInfo* info_lo = GetRegInfo(rl.reg.GetLow());
560      RegisterInfo* info_hi = GetRegInfo(rl.reg.GetHigh());
561      if (info_lo->IsTemp()) {
562        info_lo->SetIsWide(false);
563        info_lo->ResetDefBody();
564      }
565      if (info_hi->IsTemp()) {
566        info_hi->SetIsWide(false);
567        info_hi->ResetDefBody();
568      }
569      rl.reg = rl.reg.GetLow();
570    }
571  }
572  rl.wide = false;
573  return rl;
574}
575
576void Mir2Lir::ResetDefLoc(RegLocation rl) {
577  DCHECK(!rl.wide);
578  if (IsTemp(rl.reg) && !(cu_->disable_opt & (1 << kSuppressLoads))) {
579    NullifyRange(rl.reg, rl.s_reg_low);
580  }
581  ResetDef(rl.reg);
582}
583
584void Mir2Lir::ResetDefLocWide(RegLocation rl) {
585  DCHECK(rl.wide);
586  // If pair, only track low reg of pair.
587  RegStorage rs = rl.reg.IsPair() ? rl.reg.GetLow() : rl.reg;
588  if (IsTemp(rs) && !(cu_->disable_opt & (1 << kSuppressLoads))) {
589    NullifyRange(rs, rl.s_reg_low);
590  }
591  ResetDef(rs);
592}
593
594void Mir2Lir::ResetDefTracking() {
595  GrowableArray<RegisterInfo*>::Iterator core_it(&reg_pool_->core_regs_);
596  for (RegisterInfo* info = core_it.Next(); info != nullptr; info = core_it.Next()) {
597    info->ResetDefBody();
598  }
599  GrowableArray<RegisterInfo*>::Iterator sp_it(&reg_pool_->core_regs_);
600  for (RegisterInfo* info = sp_it.Next(); info != nullptr; info = sp_it.Next()) {
601    info->ResetDefBody();
602  }
603  GrowableArray<RegisterInfo*>::Iterator dp_it(&reg_pool_->core_regs_);
604  for (RegisterInfo* info = dp_it.Next(); info != nullptr; info = dp_it.Next()) {
605    info->ResetDefBody();
606  }
607}
608
609void Mir2Lir::ClobberAllRegs() {
610  GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
611  for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) {
612    info->SetIsLive(false);
613    info->SetSReg(INVALID_SREG);
614    info->ResetDefBody();
615    info->SetIsWide(false);
616  }
617}
618
619void Mir2Lir::FlushRegWide(RegStorage reg) {
620  if (reg.IsPair()) {
621    RegisterInfo* info1 = GetRegInfo(reg.GetLow());
622    RegisterInfo* info2 = GetRegInfo(reg.GetHigh());
623    DCHECK(info1 && info2 && info1->IsWide() && info2->IsWide() &&
624         (info1->Partner() == info2->GetReg()) && (info2->Partner() == info1->GetReg()));
625    if ((info1->IsLive() && info1->IsDirty()) || (info2->IsLive() && info2->IsDirty())) {
626      if (!(info1->IsTemp() && info2->IsTemp())) {
627        /* Should not happen.  If it does, there's a problem in eval_loc */
628        LOG(FATAL) << "Long half-temp, half-promoted";
629      }
630
631      info1->SetIsDirty(false);
632      info2->SetIsDirty(false);
633      if (mir_graph_->SRegToVReg(info2->SReg()) < mir_graph_->SRegToVReg(info1->SReg())) {
634        info1 = info2;
635      }
636      int v_reg = mir_graph_->SRegToVReg(info1->SReg());
637      StoreBaseDispWide(TargetReg(kSp), VRegOffset(v_reg), reg);
638    }
639  } else {
640    RegisterInfo* info = GetRegInfo(reg);
641    if (info->IsLive() && info->IsDirty()) {
642      info->SetIsDirty(false);
643      int v_reg = mir_graph_->SRegToVReg(info->SReg());
644      StoreBaseDispWide(TargetReg(kSp), VRegOffset(v_reg), reg);
645    }
646  }
647}
648
649void Mir2Lir::FlushReg(RegStorage reg) {
650  DCHECK(!reg.IsPair());
651  RegisterInfo* info = GetRegInfo(reg);
652  if (info->IsLive() && info->IsDirty()) {
653    info->SetIsDirty(false);
654    int v_reg = mir_graph_->SRegToVReg(info->SReg());
655    StoreBaseDisp(TargetReg(kSp), VRegOffset(v_reg), reg, kWord);
656  }
657}
658
659void Mir2Lir::FlushSpecificReg(RegisterInfo* info) {
660  if (info->IsWide()) {
661    FlushRegWide(info->GetReg());
662  } else {
663    FlushReg(info->GetReg());
664  }
665}
666
667void Mir2Lir::FlushAllRegs() {
668  GrowableArray<RegisterInfo*>::Iterator it(&tempreg_info_);
669  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
670    if (info->IsLive() && info->IsDirty()) {
671      FlushSpecificReg(info);
672    }
673    DCHECK(info->IsTemp());
674    info->SetIsLive(false);
675    info->SetSReg(INVALID_SREG);
676    info->ResetDefBody();
677    info->SetIsWide(false);
678  }
679}
680
681
682bool Mir2Lir::RegClassMatches(int reg_class, RegStorage reg) {
683  if (reg_class == kAnyReg) {
684    return true;
685  } else if (reg_class == kCoreReg) {
686    return !reg.IsFloat();
687  } else {
688    return reg.IsFloat();
689  }
690}
691
692void Mir2Lir::MarkLiveReg(RegStorage reg, int s_reg) {
693  RegisterInfo* info = GetRegInfo(reg);
694  if ((info->SReg() == s_reg) && info->IsLive()) {
695    return;  // Already live.
696  }
697  if (s_reg != INVALID_SREG) {
698    ClobberSReg(s_reg);
699    if (info->IsTemp()) {
700      info->SetIsLive(true);
701    }
702  } else {
703    // Can't be live if no associated s_reg.
704    DCHECK(info->IsTemp());
705    info->SetIsLive(false);
706  }
707  info->SetSReg(s_reg);
708}
709
710void Mir2Lir::MarkLive(RegLocation loc) {
711  RegStorage reg = loc.reg;
712  int s_reg = loc.s_reg_low;
713  if (reg.IsPair()) {
714    MarkLiveReg(reg.GetLow(), s_reg);
715    MarkLiveReg(reg.GetHigh(), s_reg+1);
716  } else {
717    if (loc.wide) {
718      ClobberSReg(s_reg + 1);
719    }
720    MarkLiveReg(reg, s_reg);
721  }
722}
723
724void Mir2Lir::MarkTemp(RegStorage reg) {
725  DCHECK(!reg.IsPair());
726  RegisterInfo* info = GetRegInfo(reg);
727  tempreg_info_.Insert(info);
728  info->SetIsTemp(true);
729}
730
731void Mir2Lir::UnmarkTemp(RegStorage reg) {
732  DCHECK(!reg.IsPair());
733  RegisterInfo* info = GetRegInfo(reg);
734  tempreg_info_.Delete(info);
735  info->SetIsTemp(false);
736}
737
738void Mir2Lir::MarkWide(RegStorage reg) {
739  if (reg.IsPair()) {
740    RegisterInfo* info_lo = GetRegInfo(reg.GetLow());
741    RegisterInfo* info_hi = GetRegInfo(reg.GetHigh());
742    info_lo->SetIsWide(true);
743    info_hi->SetIsWide(true);
744    info_lo->SetPartner(reg.GetHigh());
745    info_hi->SetPartner(reg.GetLow());
746  } else {
747    RegisterInfo* info = GetRegInfo(reg);
748    info->SetIsWide(true);
749    info->SetPartner(reg);
750  }
751}
752
753void Mir2Lir::MarkClean(RegLocation loc) {
754  if (loc.reg.IsPair()) {
755    RegisterInfo* info = GetRegInfo(loc.reg.GetLow());
756    info->SetIsDirty(false);
757    info = GetRegInfo(loc.reg.GetHigh());
758    info->SetIsDirty(false);
759  } else {
760    RegisterInfo* info = GetRegInfo(loc.reg);
761    info->SetIsDirty(false);
762  }
763}
764
765// FIXME: need to verify rules/assumptions about how wide values are treated in 64BitSolos.
766void Mir2Lir::MarkDirty(RegLocation loc) {
767  if (loc.home) {
768    // If already home, can't be dirty
769    return;
770  }
771  if (loc.reg.IsPair()) {
772    RegisterInfo* info = GetRegInfo(loc.reg.GetLow());
773    info->SetIsDirty(true);
774    info = GetRegInfo(loc.reg.GetHigh());
775    info->SetIsDirty(true);
776  } else {
777    RegisterInfo* info = GetRegInfo(loc.reg);
778    info->SetIsDirty(true);
779  }
780}
781
782void Mir2Lir::MarkInUse(RegStorage reg) {
783  if (reg.IsPair()) {
784    GetRegInfo(reg.GetLow())->MarkInUse();
785    GetRegInfo(reg.GetHigh())->MarkInUse();
786  } else {
787    GetRegInfo(reg)->MarkInUse();
788  }
789}
790
791bool Mir2Lir::CheckCorePoolSanity() {
792  GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->core_regs_);
793  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
794    RegStorage my_reg = info->GetReg();
795    if (info->IsWide() && my_reg.IsPair()) {
796      int my_sreg = info->SReg();
797      RegStorage partner_reg = info->Partner();
798      RegisterInfo* partner = GetRegInfo(partner_reg);
799      DCHECK(partner != NULL);
800      DCHECK(partner->IsWide());
801      DCHECK_EQ(my_reg.GetReg(), partner->Partner().GetReg());
802      int partner_sreg = partner->SReg();
803      if (my_sreg == INVALID_SREG) {
804        DCHECK_EQ(partner_sreg, INVALID_SREG);
805      } else {
806        int diff = my_sreg - partner_sreg;
807        DCHECK((diff == 0) || (diff == -1) || (diff == 1));
808      }
809    } else {
810      // TODO: add whatever sanity checks might be useful for 64BitSolo regs here.
811      // TODO: sanity checks for floating point pools?
812    }
813    if (!info->IsLive()) {
814      DCHECK(info->DefStart() == NULL);
815      DCHECK(info->DefEnd() == NULL);
816    }
817  }
818  return true;
819}
820
821/*
822 * Return an updated location record with current in-register status.
823 * If the value lives in live temps, reflect that fact.  No code
824 * is generated.  If the live value is part of an older pair,
825 * clobber both low and high.
826 * TUNING: clobbering both is a bit heavy-handed, but the alternative
827 * is a bit complex when dealing with FP regs.  Examine code to see
828 * if it's worthwhile trying to be more clever here.
829 */
830RegLocation Mir2Lir::UpdateLoc(RegLocation loc) {
831  DCHECK(!loc.wide);
832  DCHECK(CheckCorePoolSanity());
833  if (loc.location != kLocPhysReg) {
834    DCHECK((loc.location == kLocDalvikFrame) ||
835         (loc.location == kLocCompilerTemp));
836    RegStorage reg = AllocLiveReg(loc.s_reg_low, kAnyReg, false);
837    if (reg.Valid()) {
838      bool match = true;
839      RegisterInfo* info = GetRegInfo(reg);
840      match &= !reg.IsPair();
841      match &= !info->IsWide();
842      if (match) {
843        loc.location = kLocPhysReg;
844        loc.reg = reg;
845      } else {
846        Clobber(reg);
847        FreeTemp(reg);
848      }
849    }
850  }
851  return loc;
852}
853
854RegLocation Mir2Lir::UpdateLocWide(RegLocation loc) {
855  DCHECK(loc.wide);
856  DCHECK(CheckCorePoolSanity());
857  if (loc.location != kLocPhysReg) {
858    DCHECK((loc.location == kLocDalvikFrame) ||
859         (loc.location == kLocCompilerTemp));
860    RegStorage reg = AllocLiveReg(loc.s_reg_low, kAnyReg, true);
861    if (reg.Valid()) {
862      bool match = true;
863      if (reg.IsPair()) {
864        // If we've got a register pair, make sure that it was last used as the same pair.
865        RegisterInfo* info_lo = GetRegInfo(reg.GetLow());
866        RegisterInfo* info_hi = GetRegInfo(reg.GetHigh());
867        match &= info_lo->IsWide();
868        match &= info_hi->IsWide();
869        match &= (info_lo->Partner() == info_hi->GetReg());
870        match &= (info_hi->Partner() == info_lo->GetReg());
871      } else {
872        RegisterInfo* info = GetRegInfo(reg);
873        match &= info->IsWide();
874        match &= (info->GetReg() == info->Partner());
875      }
876      if (match) {
877        loc.location = kLocPhysReg;
878        loc.reg = reg;
879      } else {
880        Clobber(reg);
881        FreeTemp(reg);
882      }
883    }
884  }
885  return loc;
886}
887
888/* For use in cases we don't know (or care) width */
889RegLocation Mir2Lir::UpdateRawLoc(RegLocation loc) {
890  if (loc.wide)
891    return UpdateLocWide(loc);
892  else
893    return UpdateLoc(loc);
894}
895
896RegLocation Mir2Lir::EvalLocWide(RegLocation loc, int reg_class, bool update) {
897  DCHECK(loc.wide);
898
899  loc = UpdateLocWide(loc);
900
901  /* If already in registers, we can assume proper form.  Right reg class? */
902  if (loc.location == kLocPhysReg) {
903    if (!RegClassMatches(reg_class, loc.reg)) {
904      /* Wrong register class.  Reallocate and copy */
905      RegStorage new_regs = AllocTypedTempWide(loc.fp, reg_class);
906      OpRegCopyWide(new_regs, loc.reg);
907      // Associate the old sreg with the new register and clobber the old register.
908      GetRegInfo(new_regs)->SetSReg(GetRegInfo(loc.reg)->SReg());
909      Clobber(loc.reg);
910      loc.reg = new_regs;
911      MarkWide(loc.reg);
912    }
913    return loc;
914  }
915
916  DCHECK_NE(loc.s_reg_low, INVALID_SREG);
917  DCHECK_NE(GetSRegHi(loc.s_reg_low), INVALID_SREG);
918
919  loc.reg = AllocTypedTempWide(loc.fp, reg_class);
920  MarkWide(loc.reg);
921
922  if (update) {
923    loc.location = kLocPhysReg;
924    MarkLive(loc);
925  }
926  return loc;
927}
928
929RegLocation Mir2Lir::EvalLoc(RegLocation loc, int reg_class, bool update) {
930  if (loc.wide) {
931    return EvalLocWide(loc, reg_class, update);
932  }
933
934  loc = UpdateLoc(loc);
935
936  if (loc.location == kLocPhysReg) {
937    if (!RegClassMatches(reg_class, loc.reg)) {
938      /* Wrong register class.  Realloc, copy and transfer ownership */
939      RegStorage new_reg = AllocTypedTemp(loc.fp, reg_class);
940      OpRegCopy(new_reg, loc.reg);
941      // Associate the old sreg with the new register and clobber the old register.
942      GetRegInfo(new_reg)->SetSReg(GetRegInfo(loc.reg)->SReg());
943      Clobber(loc.reg);
944      loc.reg = new_reg;
945    }
946    return loc;
947  }
948
949  DCHECK_NE(loc.s_reg_low, INVALID_SREG);
950
951  loc.reg = AllocTypedTemp(loc.fp, reg_class);
952
953  if (update) {
954    loc.location = kLocPhysReg;
955    MarkLive(loc);
956  }
957  return loc;
958}
959
960/* USE SSA names to count references of base Dalvik v_regs. */
961void Mir2Lir::CountRefs(RefCounts* core_counts, RefCounts* fp_counts, size_t num_regs) {
962  for (int i = 0; i < mir_graph_->GetNumSSARegs(); i++) {
963    RegLocation loc = mir_graph_->reg_location_[i];
964    RefCounts* counts = loc.fp ? fp_counts : core_counts;
965    int p_map_idx = SRegToPMap(loc.s_reg_low);
966    if (loc.fp) {
967      if (loc.wide) {
968        // Treat doubles as a unit, using upper half of fp_counts array.
969        counts[p_map_idx + num_regs].count += mir_graph_->GetUseCount(i);
970        i++;
971      } else {
972        counts[p_map_idx].count += mir_graph_->GetUseCount(i);
973      }
974    } else if (!IsInexpensiveConstant(loc)) {
975      counts[p_map_idx].count += mir_graph_->GetUseCount(i);
976    }
977  }
978}
979
980/* qsort callback function, sort descending */
981static int SortCounts(const void *val1, const void *val2) {
982  const Mir2Lir::RefCounts* op1 = reinterpret_cast<const Mir2Lir::RefCounts*>(val1);
983  const Mir2Lir::RefCounts* op2 = reinterpret_cast<const Mir2Lir::RefCounts*>(val2);
984  // Note that we fall back to sorting on reg so we get stable output
985  // on differing qsort implementations (such as on host and target or
986  // between local host and build servers).
987  return (op1->count == op2->count)
988          ? (op1->s_reg - op2->s_reg)
989          : (op1->count < op2->count ? 1 : -1);
990}
991
992void Mir2Lir::DumpCounts(const RefCounts* arr, int size, const char* msg) {
993  LOG(INFO) << msg;
994  for (int i = 0; i < size; i++) {
995    if ((arr[i].s_reg & STARTING_DOUBLE_SREG) != 0) {
996      LOG(INFO) << "s_reg[D" << (arr[i].s_reg & ~STARTING_DOUBLE_SREG) << "]: " << arr[i].count;
997    } else {
998      LOG(INFO) << "s_reg[" << arr[i].s_reg << "]: " << arr[i].count;
999    }
1000  }
1001}
1002
1003/*
1004 * Note: some portions of this code required even if the kPromoteRegs
1005 * optimization is disabled.
1006 */
1007void Mir2Lir::DoPromotion() {
1008  int dalvik_regs = cu_->num_dalvik_registers;
1009  int num_regs = dalvik_regs + mir_graph_->GetNumUsedCompilerTemps();
1010  const int promotion_threshold = 1;
1011  // Allocate the promotion map - one entry for each Dalvik vReg or compiler temp
1012  promotion_map_ = static_cast<PromotionMap*>
1013      (arena_->Alloc(num_regs * sizeof(promotion_map_[0]), kArenaAllocRegAlloc));
1014
1015  // Allow target code to add any special registers
1016  AdjustSpillMask();
1017
1018  /*
1019   * Simple register promotion. Just do a static count of the uses
1020   * of Dalvik registers.  Note that we examine the SSA names, but
1021   * count based on original Dalvik register name.  Count refs
1022   * separately based on type in order to give allocation
1023   * preference to fp doubles - which must be allocated sequential
1024   * physical single fp registers starting with an even-numbered
1025   * reg.
1026   * TUNING: replace with linear scan once we have the ability
1027   * to describe register live ranges for GC.
1028   */
1029  RefCounts *core_regs =
1030      static_cast<RefCounts*>(arena_->Alloc(sizeof(RefCounts) * num_regs,
1031                                            kArenaAllocRegAlloc));
1032  RefCounts *FpRegs =
1033      static_cast<RefCounts *>(arena_->Alloc(sizeof(RefCounts) * num_regs * 2,
1034                                             kArenaAllocRegAlloc));
1035  // Set ssa names for original Dalvik registers
1036  for (int i = 0; i < dalvik_regs; i++) {
1037    core_regs[i].s_reg = FpRegs[i].s_reg = i;
1038  }
1039
1040  // Set ssa names for compiler temporaries
1041  for (unsigned int ct_idx = 0; ct_idx < mir_graph_->GetNumUsedCompilerTemps(); ct_idx++) {
1042    CompilerTemp* ct = mir_graph_->GetCompilerTemp(ct_idx);
1043    core_regs[dalvik_regs + ct_idx].s_reg = ct->s_reg_low;
1044    FpRegs[dalvik_regs + ct_idx].s_reg = ct->s_reg_low;
1045    FpRegs[num_regs + dalvik_regs + ct_idx].s_reg = ct->s_reg_low;
1046  }
1047
1048  // Duplicate in upper half to represent possible fp double starting sregs.
1049  for (int i = 0; i < num_regs; i++) {
1050    FpRegs[num_regs + i].s_reg = FpRegs[i].s_reg | STARTING_DOUBLE_SREG;
1051  }
1052
1053  // Sum use counts of SSA regs by original Dalvik vreg.
1054  CountRefs(core_regs, FpRegs, num_regs);
1055
1056
1057  // Sort the count arrays
1058  qsort(core_regs, num_regs, sizeof(RefCounts), SortCounts);
1059  qsort(FpRegs, num_regs * 2, sizeof(RefCounts), SortCounts);
1060
1061  if (cu_->verbose) {
1062    DumpCounts(core_regs, num_regs, "Core regs after sort");
1063    DumpCounts(FpRegs, num_regs * 2, "Fp regs after sort");
1064  }
1065
1066  if (!(cu_->disable_opt & (1 << kPromoteRegs))) {
1067    // Promote FpRegs
1068    for (int i = 0; (i < (num_regs * 2)) && (FpRegs[i].count >= promotion_threshold); i++) {
1069      int p_map_idx = SRegToPMap(FpRegs[i].s_reg & ~STARTING_DOUBLE_SREG);
1070      if ((FpRegs[i].s_reg & STARTING_DOUBLE_SREG) != 0) {
1071        if ((promotion_map_[p_map_idx].fp_location != kLocPhysReg) &&
1072            (promotion_map_[p_map_idx + 1].fp_location != kLocPhysReg)) {
1073          int low_sreg = FpRegs[i].s_reg & ~STARTING_DOUBLE_SREG;
1074          // Ignore result - if can't alloc double may still be able to alloc singles.
1075          AllocPreservedDouble(low_sreg);
1076        }
1077      } else if (promotion_map_[p_map_idx].fp_location != kLocPhysReg) {
1078        RegStorage reg = AllocPreservedSingle(FpRegs[i].s_reg);
1079        if (!reg.Valid()) {
1080          break;  // No more left.
1081        }
1082      }
1083    }
1084
1085    // Promote core regs
1086    for (int i = 0; (i < num_regs) &&
1087            (core_regs[i].count >= promotion_threshold); i++) {
1088      int p_map_idx = SRegToPMap(core_regs[i].s_reg);
1089      if (promotion_map_[p_map_idx].core_location !=
1090          kLocPhysReg) {
1091        RegStorage reg = AllocPreservedCoreReg(core_regs[i].s_reg);
1092        if (!reg.Valid()) {
1093           break;  // No more left
1094        }
1095      }
1096    }
1097  }
1098
1099  // Now, update SSA names to new home locations
1100  for (int i = 0; i < mir_graph_->GetNumSSARegs(); i++) {
1101    RegLocation *curr = &mir_graph_->reg_location_[i];
1102    int p_map_idx = SRegToPMap(curr->s_reg_low);
1103    if (!curr->wide) {
1104      if (curr->fp) {
1105        if (promotion_map_[p_map_idx].fp_location == kLocPhysReg) {
1106          curr->location = kLocPhysReg;
1107          curr->reg = RegStorage::Solo32(promotion_map_[p_map_idx].FpReg);
1108          curr->home = true;
1109        }
1110      } else {
1111        if (promotion_map_[p_map_idx].core_location == kLocPhysReg) {
1112          curr->location = kLocPhysReg;
1113          curr->reg = RegStorage::Solo32(promotion_map_[p_map_idx].core_reg);
1114          curr->home = true;
1115        }
1116      }
1117    } else {
1118      if (curr->high_word) {
1119        continue;
1120      }
1121      if (curr->fp) {
1122        if ((promotion_map_[p_map_idx].fp_location == kLocPhysReg) &&
1123            (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg)) {
1124          int low_reg = promotion_map_[p_map_idx].FpReg;
1125          int high_reg = promotion_map_[p_map_idx+1].FpReg;
1126          // Doubles require pair of singles starting at even reg
1127          // TODO: move target-specific restrictions out of here.
1128          if (((low_reg & 0x1) == 0) && ((low_reg + 1) == high_reg)) {
1129            curr->location = kLocPhysReg;
1130            if (cu_->instruction_set == kThumb2) {
1131              curr->reg = RegStorage::FloatSolo64(RegStorage::RegNum(low_reg) >> 1);
1132            } else {
1133              curr->reg = RegStorage(RegStorage::k64BitPair, low_reg, high_reg);
1134            }
1135            curr->home = true;
1136          }
1137        }
1138      } else {
1139        if ((promotion_map_[p_map_idx].core_location == kLocPhysReg)
1140           && (promotion_map_[p_map_idx+1].core_location ==
1141           kLocPhysReg)) {
1142          curr->location = kLocPhysReg;
1143          curr->reg = RegStorage(RegStorage::k64BitPair, promotion_map_[p_map_idx].core_reg,
1144                                 promotion_map_[p_map_idx+1].core_reg);
1145          curr->home = true;
1146        }
1147      }
1148    }
1149  }
1150  if (cu_->verbose) {
1151    DumpPromotionMap();
1152  }
1153}
1154
1155/* Returns sp-relative offset in bytes for a VReg */
1156int Mir2Lir::VRegOffset(int v_reg) {
1157  return StackVisitor::GetVRegOffset(cu_->code_item, core_spill_mask_,
1158                                     fp_spill_mask_, frame_size_, v_reg,
1159                                     cu_->instruction_set);
1160}
1161
1162/* Returns sp-relative offset in bytes for a SReg */
1163int Mir2Lir::SRegOffset(int s_reg) {
1164  return VRegOffset(mir_graph_->SRegToVReg(s_reg));
1165}
1166
1167/* Mark register usage state and return long retloc */
1168RegLocation Mir2Lir::GetReturnWide(bool is_double) {
1169  RegLocation gpr_res = LocCReturnWide();
1170  RegLocation fpr_res = LocCReturnDouble();
1171  RegLocation res = is_double ? fpr_res : gpr_res;
1172  if (res.reg.IsPair()) {
1173    Clobber(res.reg);
1174    LockTemp(res.reg);
1175    // Does this wide value live in two registers or one vector register?
1176    if (res.reg.GetLowReg() != res.reg.GetHighReg()) {
1177      // FIXME: I think we want to mark these as wide as well.
1178      MarkWide(res.reg);
1179    }
1180  } else {
1181    Clobber(res.reg);
1182    LockTemp(res.reg);
1183    MarkWide(res.reg);
1184  }
1185  return res;
1186}
1187
1188RegLocation Mir2Lir::GetReturn(bool is_float) {
1189  RegLocation gpr_res = LocCReturn();
1190  RegLocation fpr_res = LocCReturnFloat();
1191  RegLocation res = is_float ? fpr_res : gpr_res;
1192  Clobber(res.reg);
1193  if (cu_->instruction_set == kMips) {
1194    MarkInUse(res.reg);
1195  } else {
1196    LockTemp(res.reg);
1197  }
1198  return res;
1199}
1200
1201void Mir2Lir::SimpleRegAlloc() {
1202  DoPromotion();
1203
1204  if (cu_->verbose && !(cu_->disable_opt & (1 << kPromoteRegs))) {
1205    LOG(INFO) << "After Promotion";
1206    mir_graph_->DumpRegLocTable(mir_graph_->reg_location_, mir_graph_->GetNumSSARegs());
1207  }
1208
1209  /* Set the frame size */
1210  frame_size_ = ComputeFrameSize();
1211}
1212
1213/*
1214 * Get the "real" sreg number associated with an s_reg slot.  In general,
1215 * s_reg values passed through codegen are the SSA names created by
1216 * dataflow analysis and refer to slot numbers in the mir_graph_->reg_location
1217 * array.  However, renaming is accomplished by simply replacing RegLocation
1218 * entries in the reglocation[] array.  Therefore, when location
1219 * records for operands are first created, we need to ask the locRecord
1220 * identified by the dataflow pass what it's new name is.
1221 */
1222int Mir2Lir::GetSRegHi(int lowSreg) {
1223  return (lowSreg == INVALID_SREG) ? INVALID_SREG : lowSreg + 1;
1224}
1225
1226bool Mir2Lir::LiveOut(int s_reg) {
1227  // For now.
1228  return true;
1229}
1230
1231}  // namespace art
1232