1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "codegen_mips.h"
18
19#include <inttypes.h>
20
21#include <string>
22
23#include "arch/mips/instruction_set_features_mips.h"
24#include "backend_mips.h"
25#include "base/logging.h"
26#include "dex/compiler_ir.h"
27#include "dex/quick/mir_to_lir-inl.h"
28#include "driver/compiler_driver.h"
29#include "mips_lir.h"
30
31namespace art {
32
33static constexpr RegStorage core_regs_arr_32[] =
34    {rs_rZERO, rs_rAT, rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rT0_32, rs_rT1_32,
35     rs_rT2_32, rs_rT3_32, rs_rT4_32, rs_rT5_32, rs_rT6_32, rs_rT7_32, rs_rS0, rs_rS1, rs_rS2,
36     rs_rS3, rs_rS4, rs_rS5, rs_rS6, rs_rS7, rs_rT8, rs_rT9, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rFP,
37     rs_rRA};
38static constexpr RegStorage sp_regs_arr_32[] =
39    {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
40     rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
41static constexpr RegStorage dp_fr0_regs_arr_32[] =
42    {rs_rD0_fr0, rs_rD1_fr0, rs_rD2_fr0, rs_rD3_fr0, rs_rD4_fr0, rs_rD5_fr0, rs_rD6_fr0,
43     rs_rD7_fr0};
44static constexpr RegStorage dp_fr1_regs_arr_32[] =
45    {rs_rD0_fr1, rs_rD1_fr1, rs_rD2_fr1, rs_rD3_fr1, rs_rD4_fr1, rs_rD5_fr1, rs_rD6_fr1,
46     rs_rD7_fr1};
47static constexpr RegStorage reserved_regs_arr_32[] =
48    {rs_rZERO, rs_rAT, rs_rS0, rs_rS1, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rRA};
49static constexpr RegStorage core_temps_arr_32[] =
50    {rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rT0_32, rs_rT1_32, rs_rT2_32, rs_rT3_32,
51     rs_rT4_32, rs_rT5_32, rs_rT6_32, rs_rT7_32, rs_rT8};
52static constexpr RegStorage sp_fr0_temps_arr_32[] =
53    {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
54     rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
55static constexpr RegStorage sp_fr1_temps_arr_32[] =
56    {rs_rF0, rs_rF2, rs_rF4, rs_rF6, rs_rF8, rs_rF10, rs_rF12, rs_rF14};
57static constexpr RegStorage dp_fr0_temps_arr_32[] =
58    {rs_rD0_fr0, rs_rD1_fr0, rs_rD2_fr0, rs_rD3_fr0, rs_rD4_fr0, rs_rD5_fr0, rs_rD6_fr0,
59     rs_rD7_fr0};
60static constexpr RegStorage dp_fr1_temps_arr_32[] =
61    {rs_rD0_fr1, rs_rD1_fr1, rs_rD2_fr1, rs_rD3_fr1, rs_rD4_fr1, rs_rD5_fr1, rs_rD6_fr1,
62     rs_rD7_fr1};
63
64static constexpr RegStorage core_regs_arr_64[] =
65    {rs_rZERO, rs_rAT, rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rA4, rs_rA5, rs_rA6,
66     rs_rA7, rs_rT0, rs_rT1, rs_rT2, rs_rT3, rs_rS0, rs_rS1, rs_rS2, rs_rS3, rs_rS4, rs_rS5, rs_rS6,
67     rs_rS7, rs_rT8, rs_rT9, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rFP, rs_rRA};
68static constexpr RegStorage core_regs_arr_64d[] =
69    {rs_rZEROd, rs_rATd, rs_rV0d, rs_rV1d, rs_rA0d, rs_rA1d, rs_rA2d, rs_rA3d, rs_rA4d, rs_rA5d,
70     rs_rA6d, rs_rA7d, rs_rT0d, rs_rT1d, rs_rT2d, rs_rT3d, rs_rS0d, rs_rS1d, rs_rS2d, rs_rS3d,
71     rs_rS4d, rs_rS5d, rs_rS6d, rs_rS7d, rs_rT8d, rs_rT9d, rs_rK0d, rs_rK1d, rs_rGPd, rs_rSPd,
72     rs_rFPd, rs_rRAd};
73#if 0
74// TODO: f24-f31 must be saved before calls and restored after.
75static constexpr RegStorage sp_regs_arr_64[] =
76    {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
77     rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15, rs_rF16, rs_rF17, rs_rF18, rs_rF19, rs_rF20,
78     rs_rF21, rs_rF22, rs_rF23, rs_rF24, rs_rF25, rs_rF26, rs_rF27, rs_rF28, rs_rF29, rs_rF30,
79     rs_rF31};
80static constexpr RegStorage dp_regs_arr_64[] =
81    {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7, rs_rD8, rs_rD9, rs_rD10,
82     rs_rD11, rs_rD12, rs_rD13, rs_rD14, rs_rD15, rs_rD16, rs_rD17, rs_rD18, rs_rD19, rs_rD20,
83     rs_rD21, rs_rD22, rs_rD23, rs_rD24, rs_rD25, rs_rD26, rs_rD27, rs_rD28, rs_rD29, rs_rD30,
84     rs_rD31};
85#else
86static constexpr RegStorage sp_regs_arr_64[] =
87    {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
88     rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15, rs_rF16, rs_rF17, rs_rF18, rs_rF19, rs_rF20,
89     rs_rF21, rs_rF22, rs_rF23};
90static constexpr RegStorage dp_regs_arr_64[] =
91    {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7, rs_rD8, rs_rD9, rs_rD10,
92     rs_rD11, rs_rD12, rs_rD13, rs_rD14, rs_rD15, rs_rD16, rs_rD17, rs_rD18, rs_rD19, rs_rD20,
93     rs_rD21, rs_rD22, rs_rD23};
94#endif
95static constexpr RegStorage reserved_regs_arr_64[] =
96    {rs_rZERO, rs_rAT, rs_rS0, rs_rS1, rs_rT9, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rRA};
97static constexpr RegStorage reserved_regs_arr_64d[] =
98    {rs_rZEROd, rs_rATd, rs_rS0d, rs_rS1d, rs_rT9d, rs_rK0d, rs_rK1d, rs_rGPd, rs_rSPd, rs_rRAd};
99static constexpr RegStorage core_temps_arr_64[] =
100    {rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rA4, rs_rA5, rs_rA6, rs_rA7, rs_rT0, rs_rT1,
101     rs_rT2, rs_rT3, rs_rT8};
102static constexpr RegStorage core_temps_arr_64d[] =
103    {rs_rV0d, rs_rV1d, rs_rA0d, rs_rA1d, rs_rA2d, rs_rA3d, rs_rA4d, rs_rA5d, rs_rA6d, rs_rA7d,
104     rs_rT0d, rs_rT1d, rs_rT2d, rs_rT3d, rs_rT8d};
105#if 0
106// TODO: f24-f31 must be saved before calls and restored after.
107static constexpr RegStorage sp_temps_arr_64[] =
108    {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
109     rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15, rs_rF16, rs_rF17, rs_rF18, rs_rF19, rs_rF20,
110     rs_rF21, rs_rF22, rs_rF23, rs_rF24, rs_rF25, rs_rF26, rs_rF27, rs_rF28, rs_rF29, rs_rF30,
111     rs_rF31};
112static constexpr RegStorage dp_temps_arr_64[] =
113    {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7, rs_rD8, rs_rD9, rs_rD10,
114     rs_rD11, rs_rD12, rs_rD13, rs_rD14, rs_rD15, rs_rD16, rs_rD17, rs_rD18, rs_rD19, rs_rD20,
115     rs_rD21, rs_rD22, rs_rD23, rs_rD24, rs_rD25, rs_rD26, rs_rD27, rs_rD28, rs_rD29, rs_rD30,
116     rs_rD31};
117#else
118static constexpr RegStorage sp_temps_arr_64[] =
119    {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
120     rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15, rs_rF16, rs_rF17, rs_rF18, rs_rF19, rs_rF20,
121     rs_rF21, rs_rF22, rs_rF23};
122static constexpr RegStorage dp_temps_arr_64[] =
123    {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7, rs_rD8, rs_rD9, rs_rD10,
124     rs_rD11, rs_rD12, rs_rD13, rs_rD14, rs_rD15, rs_rD16, rs_rD17, rs_rD18, rs_rD19, rs_rD20,
125     rs_rD21, rs_rD22, rs_rD23};
126#endif
127
128static constexpr ArrayRef<const RegStorage> empty_pool;
129static constexpr ArrayRef<const RegStorage> core_regs_32(core_regs_arr_32);
130static constexpr ArrayRef<const RegStorage> sp_regs_32(sp_regs_arr_32);
131static constexpr ArrayRef<const RegStorage> dp_fr0_regs_32(dp_fr0_regs_arr_32);
132static constexpr ArrayRef<const RegStorage> dp_fr1_regs_32(dp_fr1_regs_arr_32);
133static constexpr ArrayRef<const RegStorage> reserved_regs_32(reserved_regs_arr_32);
134static constexpr ArrayRef<const RegStorage> core_temps_32(core_temps_arr_32);
135static constexpr ArrayRef<const RegStorage> sp_fr0_temps_32(sp_fr0_temps_arr_32);
136static constexpr ArrayRef<const RegStorage> sp_fr1_temps_32(sp_fr1_temps_arr_32);
137static constexpr ArrayRef<const RegStorage> dp_fr0_temps_32(dp_fr0_temps_arr_32);
138static constexpr ArrayRef<const RegStorage> dp_fr1_temps_32(dp_fr1_temps_arr_32);
139
140static constexpr ArrayRef<const RegStorage> core_regs_64(core_regs_arr_64);
141static constexpr ArrayRef<const RegStorage> core_regs_64d(core_regs_arr_64d);
142static constexpr ArrayRef<const RegStorage> sp_regs_64(sp_regs_arr_64);
143static constexpr ArrayRef<const RegStorage> dp_regs_64(dp_regs_arr_64);
144static constexpr ArrayRef<const RegStorage> reserved_regs_64(reserved_regs_arr_64);
145static constexpr ArrayRef<const RegStorage> reserved_regs_64d(reserved_regs_arr_64d);
146static constexpr ArrayRef<const RegStorage> core_temps_64(core_temps_arr_64);
147static constexpr ArrayRef<const RegStorage> core_temps_64d(core_temps_arr_64d);
148static constexpr ArrayRef<const RegStorage> sp_temps_64(sp_temps_arr_64);
149static constexpr ArrayRef<const RegStorage> dp_temps_64(dp_temps_arr_64);
150
151RegLocation MipsMir2Lir::LocCReturn() {
152  return mips_loc_c_return;
153}
154
155RegLocation MipsMir2Lir::LocCReturnRef() {
156  return cu_->target64 ? mips64_loc_c_return_ref : mips_loc_c_return;
157}
158
159RegLocation MipsMir2Lir::LocCReturnWide() {
160  return cu_->target64 ? mips64_loc_c_return_wide : mips_loc_c_return_wide;
161}
162
163RegLocation MipsMir2Lir::LocCReturnFloat() {
164  return mips_loc_c_return_float;
165}
166
167RegLocation MipsMir2Lir::LocCReturnDouble() {
168  if (cu_->target64) {
169    return mips64_loc_c_return_double;
170  } else if (fpuIs32Bit_) {
171    return mips_loc_c_return_double_fr0;
172  } else {
173    return mips_loc_c_return_double_fr1;
174  }
175}
176
177// Convert k64BitSolo into k64BitPair.
178RegStorage MipsMir2Lir::Solo64ToPair64(RegStorage reg) {
179  DCHECK(reg.IsDouble());
180  DCHECK_EQ(reg.GetRegNum() & 1, 0);
181  int reg_num = (reg.GetRegNum() & ~1) | RegStorage::kFloatingPoint;
182  return RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1);
183}
184
185// Convert 64bit FP (k64BitSolo or k64BitPair) into k32BitSolo.
186// This routine is only used to allow a 64bit FPU to access FP registers 32bits at a time.
187RegStorage MipsMir2Lir::Fp64ToSolo32(RegStorage reg) {
188  DCHECK(!fpuIs32Bit_);
189  DCHECK(reg.IsDouble());
190  DCHECK(!reg.IsPair());
191  int reg_num = reg.GetRegNum() | RegStorage::kFloatingPoint;
192  return RegStorage(RegStorage::k32BitSolo, reg_num);
193}
194
195// Return a target-dependent special register.
196RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg, WideKind wide_kind) {
197  if (!cu_->target64 && wide_kind == kWide) {
198    DCHECK((kArg0 <= reg && reg < kArg7) || (kFArg0 <= reg && reg < kFArg15) || (kRet0 == reg));
199    RegStorage ret_reg = RegStorage::MakeRegPair(TargetReg(reg),
200                                     TargetReg(static_cast<SpecialTargetRegister>(reg + 1)));
201    if (!fpuIs32Bit_ && ret_reg.IsFloat()) {
202      // convert 64BitPair to 64BitSolo for 64bit FPUs.
203      RegStorage low = ret_reg.GetLow();
204      ret_reg = RegStorage::FloatSolo64(low.GetRegNum());
205    }
206    return ret_reg;
207  } else if (cu_->target64 && (wide_kind == kWide || wide_kind == kRef)) {
208    return As64BitReg(TargetReg(reg));
209  } else {
210    return TargetReg(reg);
211  }
212}
213
214// Return a target-dependent special register.
215RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg) {
216  RegStorage res_reg;
217  switch (reg) {
218    case kSelf: res_reg = rs_rS1; break;
219    case kSuspend: res_reg =  rs_rS0; break;
220    case kLr: res_reg =  rs_rRA; break;
221    case kPc: res_reg = RegStorage::InvalidReg(); break;
222    case kSp: res_reg =  rs_rSP; break;
223    case kArg0: res_reg = rs_rA0; break;
224    case kArg1: res_reg = rs_rA1; break;
225    case kArg2: res_reg = rs_rA2; break;
226    case kArg3: res_reg = rs_rA3; break;
227    case kArg4: res_reg = cu_->target64 ? rs_rA4 : RegStorage::InvalidReg(); break;
228    case kArg5: res_reg = cu_->target64 ? rs_rA5 : RegStorage::InvalidReg(); break;
229    case kArg6: res_reg = cu_->target64 ? rs_rA6 : RegStorage::InvalidReg(); break;
230    case kArg7: res_reg = cu_->target64 ? rs_rA7 : RegStorage::InvalidReg(); break;
231    case kFArg0: res_reg = rs_rF12; break;
232    case kFArg1: res_reg = rs_rF13; break;
233    case kFArg2: res_reg = rs_rF14; break;
234    case kFArg3: res_reg = rs_rF15; break;
235    case kFArg4: res_reg = cu_->target64 ? rs_rF16 : RegStorage::InvalidReg(); break;
236    case kFArg5: res_reg = cu_->target64 ? rs_rF17 : RegStorage::InvalidReg(); break;
237    case kFArg6: res_reg = cu_->target64 ? rs_rF18 : RegStorage::InvalidReg(); break;
238    case kFArg7: res_reg = cu_->target64 ? rs_rF19 : RegStorage::InvalidReg(); break;
239    case kRet0: res_reg = rs_rV0; break;
240    case kRet1: res_reg = rs_rV1; break;
241    case kInvokeTgt: res_reg = rs_rT9; break;
242    case kHiddenArg: res_reg = cu_->target64 ? rs_rT0 : rs_rT0_32; break;
243    case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
244    case kCount: res_reg = RegStorage::InvalidReg(); break;
245    default: res_reg = RegStorage::InvalidReg();
246  }
247  return res_reg;
248}
249
250RegStorage MipsMir2Lir::InToRegStorageMipsMapper::GetNextReg(ShortyArg arg) {
251  const SpecialTargetRegister coreArgMappingToPhysicalReg[] = {kArg1, kArg2, kArg3};
252  const size_t coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg);
253
254  RegStorage result = RegStorage::InvalidReg();
255  if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
256    result = m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++],
257                             arg.IsRef() ? kRef : kNotWide);
258    if (arg.IsWide() && cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
259      result = RegStorage::MakeRegPair(
260          result, m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++], kNotWide));
261    }
262  }
263  return result;
264}
265
266RegStorage MipsMir2Lir::InToRegStorageMips64Mapper::GetNextReg(ShortyArg arg) {
267  const SpecialTargetRegister coreArgMappingToPhysicalReg[] =
268      {kArg1, kArg2, kArg3, kArg4, kArg5, kArg6, kArg7};
269  const size_t coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg);
270  const SpecialTargetRegister fpArgMappingToPhysicalReg[] =
271      {kFArg1, kFArg2, kFArg3, kFArg4, kFArg5, kFArg6, kFArg7};
272  const size_t fpArgMappingToPhysicalRegSize = arraysize(fpArgMappingToPhysicalReg);
273
274  RegStorage result = RegStorage::InvalidReg();
275  if (arg.IsFP()) {
276    if (cur_arg_reg_ < fpArgMappingToPhysicalRegSize) {
277      DCHECK(!arg.IsRef());
278      result = m2l_->TargetReg(fpArgMappingToPhysicalReg[cur_arg_reg_++],
279                               arg.IsWide() ? kWide : kNotWide);
280    }
281  } else {
282    if (cur_arg_reg_ < coreArgMappingToPhysicalRegSize) {
283      DCHECK(!(arg.IsWide() && arg.IsRef()));
284      result = m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_arg_reg_++],
285                               arg.IsRef() ? kRef : (arg.IsWide() ? kWide : kNotWide));
286    }
287  }
288  return result;
289}
290
291/*
292 * Decode the register id.
293 */
294ResourceMask MipsMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
295  if (cu_->target64) {
296    return ResourceMask::Bit((reg.IsFloat() ? kMipsFPReg0 : 0) + reg.GetRegNum());
297  } else {
298    if (reg.IsDouble()) {
299      return ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0);
300    } else if (reg.IsSingle()) {
301      return ResourceMask::Bit(reg.GetRegNum() + kMipsFPReg0);
302    } else {
303      return ResourceMask::Bit(reg.GetRegNum());
304    }
305  }
306}
307
308ResourceMask MipsMir2Lir::GetPCUseDefEncoding() const {
309  return cu_->target64 ? ResourceMask::Bit(kMips64RegPC) : ResourceMask::Bit(kMipsRegPC);
310}
311
312void MipsMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags, ResourceMask* use_mask,
313                                           ResourceMask* def_mask) {
314  DCHECK(!lir->flags.use_def_invalid);
315
316  // Mips-specific resource map setup here.
317  if (flags & REG_DEF_SP) {
318    def_mask->SetBit(kMipsRegSP);
319  }
320
321  if (flags & REG_USE_SP) {
322    use_mask->SetBit(kMipsRegSP);
323  }
324
325  if (flags & REG_DEF_LR) {
326    def_mask->SetBit(kMipsRegLR);
327  }
328
329  if (!cu_->target64) {
330    if (flags & REG_DEF_HI) {
331      def_mask->SetBit(kMipsRegHI);
332    }
333
334    if (flags & REG_DEF_LO) {
335      def_mask->SetBit(kMipsRegLO);
336    }
337
338    if (flags & REG_USE_HI) {
339      use_mask->SetBit(kMipsRegHI);
340    }
341
342    if (flags & REG_USE_LO) {
343      use_mask->SetBit(kMipsRegLO);
344    }
345  }
346}
347
348/* For dumping instructions */
349#define MIPS_REG_COUNT 32
350static const char *mips_reg_name[MIPS_REG_COUNT] = {
351  "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
352  "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
353  "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
354  "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
355};
356
357static const char *mips64_reg_name[MIPS_REG_COUNT] = {
358  "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
359  "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
360  "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
361  "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
362};
363
364/*
365 * Interpret a format string and build a string no longer than size
366 * See format key in assemble_mips.cc.
367 */
368std::string MipsMir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr) {
369  std::string buf;
370  int i;
371  const char *fmt_end = &fmt[strlen(fmt)];
372  char tbuf[256];
373  char nc;
374  while (fmt < fmt_end) {
375    int operand;
376    if (*fmt == '!') {
377      fmt++;
378      DCHECK_LT(fmt, fmt_end);
379      nc = *fmt++;
380      if (nc == '!') {
381        strcpy(tbuf, "!");
382      } else {
383        DCHECK_LT(fmt, fmt_end);
384        DCHECK_LT(static_cast<unsigned>(nc-'0'), 4u);
385        operand = lir->operands[nc-'0'];
386        switch (*fmt++) {
387          case 'b':
388            strcpy(tbuf, "0000");
389            for (i = 3; i >= 0; i--) {
390              tbuf[i] += operand & 1;
391              operand >>= 1;
392            }
393            break;
394          case 's':
395            snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
396            break;
397          case 'S':
398            DCHECK_EQ(RegStorage::RegNum(operand) & 1, 0);
399            snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
400            break;
401          case 'h':
402            snprintf(tbuf, arraysize(tbuf), "%04x", operand);
403            break;
404          case 'M':
405          case 'd':
406            snprintf(tbuf, arraysize(tbuf), "%d", operand);
407            break;
408          case 'D':
409            snprintf(tbuf, arraysize(tbuf), "%d", operand+1);
410            break;
411          case 'E':
412            snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
413            break;
414          case 'F':
415            snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
416            break;
417          case 't':
418            snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
419                     reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
420                     lir->target);
421            break;
422          case 'T':
423            snprintf(tbuf, arraysize(tbuf), "0x%08x", operand << 2);
424            break;
425          case 'u': {
426            int offset_1 = lir->operands[0];
427            int offset_2 = NEXT_LIR(lir)->operands[0];
428            uintptr_t target =
429                (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
430                    (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
431            snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void*>(target));
432            break;
433          }
434
435          /* Nothing to print for BLX_2 */
436          case 'v':
437            strcpy(tbuf, "see above");
438            break;
439          case 'r':
440            DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
441            if (cu_->target64) {
442              strcpy(tbuf, mips64_reg_name[operand]);
443            } else {
444              strcpy(tbuf, mips_reg_name[operand]);
445            }
446            break;
447          case 'N':
448            // Placeholder for delay slot handling
449            strcpy(tbuf, ";  nop");
450            break;
451          default:
452            strcpy(tbuf, "DecodeError");
453            break;
454        }
455        buf += tbuf;
456      }
457    } else {
458      buf += *fmt++;
459    }
460  }
461  return buf;
462}
463
464// FIXME: need to redo resource maps for MIPS - fix this at that time.
465void MipsMir2Lir::DumpResourceMask(LIR *mips_lir, const ResourceMask& mask, const char *prefix) {
466  char buf[256];
467  buf[0] = 0;
468
469  if (mask.Equals(kEncodeAll)) {
470    strcpy(buf, "all");
471  } else {
472    char num[8];
473    int i;
474
475    for (i = 0; i < (cu_->target64 ? kMips64RegEnd : kMipsRegEnd); i++) {
476      if (mask.HasBit(i)) {
477        snprintf(num, arraysize(num), "%d ", i);
478        strcat(buf, num);
479      }
480    }
481
482    if (mask.HasBit(ResourceMask::kCCode)) {
483      strcat(buf, "cc ");
484    }
485    if (mask.HasBit(ResourceMask::kFPStatus)) {
486      strcat(buf, "fpcc ");
487    }
488    // Memory bits.
489    if (mips_lir && (mask.HasBit(ResourceMask::kDalvikReg))) {
490      snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
491               DECODE_ALIAS_INFO_REG(mips_lir->flags.alias_info),
492               DECODE_ALIAS_INFO_WIDE(mips_lir->flags.alias_info) ? "(+1)" : "");
493    }
494    if (mask.HasBit(ResourceMask::kLiteral)) {
495      strcat(buf, "lit ");
496    }
497
498    if (mask.HasBit(ResourceMask::kHeapRef)) {
499      strcat(buf, "heap ");
500    }
501    if (mask.HasBit(ResourceMask::kMustNotAlias)) {
502      strcat(buf, "noalias ");
503    }
504  }
505  if (buf[0]) {
506    LOG(INFO) << prefix << ": " <<  buf;
507  }
508}
509
510/*
511 * TUNING: is true leaf?  Can't just use METHOD_IS_LEAF to determine as some
512 * instructions might call out to C/assembly helper functions.  Until
513 * machinery is in place, always spill lr.
514 */
515
516void MipsMir2Lir::AdjustSpillMask() {
517  core_spill_mask_ |= (1 << rs_rRA.GetRegNum());
518  num_core_spills_++;
519}
520
521/* Clobber all regs that might be used by an external C call */
522void MipsMir2Lir::ClobberCallerSave() {
523  if (cu_->target64) {
524    Clobber(rs_rZEROd);
525    Clobber(rs_rATd);
526    Clobber(rs_rV0d);
527    Clobber(rs_rV1d);
528    Clobber(rs_rA0d);
529    Clobber(rs_rA1d);
530    Clobber(rs_rA2d);
531    Clobber(rs_rA3d);
532    Clobber(rs_rA4d);
533    Clobber(rs_rA5d);
534    Clobber(rs_rA6d);
535    Clobber(rs_rA7d);
536    Clobber(rs_rT0d);
537    Clobber(rs_rT1d);
538    Clobber(rs_rT2d);
539    Clobber(rs_rT3d);
540    Clobber(rs_rT8d);
541    Clobber(rs_rT9d);
542    Clobber(rs_rK0d);
543    Clobber(rs_rK1d);
544    Clobber(rs_rGPd);
545    Clobber(rs_rFPd);
546    Clobber(rs_rRAd);
547
548    Clobber(rs_rF0);
549    Clobber(rs_rF1);
550    Clobber(rs_rF2);
551    Clobber(rs_rF3);
552    Clobber(rs_rF4);
553    Clobber(rs_rF5);
554    Clobber(rs_rF6);
555    Clobber(rs_rF7);
556    Clobber(rs_rF8);
557    Clobber(rs_rF9);
558    Clobber(rs_rF10);
559    Clobber(rs_rF11);
560    Clobber(rs_rF12);
561    Clobber(rs_rF13);
562    Clobber(rs_rF14);
563    Clobber(rs_rF15);
564    Clobber(rs_rD0);
565    Clobber(rs_rD1);
566    Clobber(rs_rD2);
567    Clobber(rs_rD3);
568    Clobber(rs_rD4);
569    Clobber(rs_rD5);
570    Clobber(rs_rD6);
571    Clobber(rs_rD7);
572  } else {
573    Clobber(rs_rZERO);
574    Clobber(rs_rAT);
575    Clobber(rs_rV0);
576    Clobber(rs_rV1);
577    Clobber(rs_rA0);
578    Clobber(rs_rA1);
579    Clobber(rs_rA2);
580    Clobber(rs_rA3);
581    Clobber(rs_rT0_32);
582    Clobber(rs_rT1_32);
583    Clobber(rs_rT2_32);
584    Clobber(rs_rT3_32);
585    Clobber(rs_rT4_32);
586    Clobber(rs_rT5_32);
587    Clobber(rs_rT6_32);
588    Clobber(rs_rT7_32);
589    Clobber(rs_rT8);
590    Clobber(rs_rT9);
591    Clobber(rs_rK0);
592    Clobber(rs_rK1);
593    Clobber(rs_rGP);
594    Clobber(rs_rFP);
595    Clobber(rs_rRA);
596    Clobber(rs_rF0);
597    Clobber(rs_rF2);
598    Clobber(rs_rF4);
599    Clobber(rs_rF6);
600    Clobber(rs_rF8);
601    Clobber(rs_rF10);
602    Clobber(rs_rF12);
603    Clobber(rs_rF14);
604    if (fpuIs32Bit_) {
605      Clobber(rs_rF1);
606      Clobber(rs_rF3);
607      Clobber(rs_rF5);
608      Clobber(rs_rF7);
609      Clobber(rs_rF9);
610      Clobber(rs_rF11);
611      Clobber(rs_rF13);
612      Clobber(rs_rF15);
613      Clobber(rs_rD0_fr0);
614      Clobber(rs_rD1_fr0);
615      Clobber(rs_rD2_fr0);
616      Clobber(rs_rD3_fr0);
617      Clobber(rs_rD4_fr0);
618      Clobber(rs_rD5_fr0);
619      Clobber(rs_rD6_fr0);
620      Clobber(rs_rD7_fr0);
621    } else {
622      Clobber(rs_rD0_fr1);
623      Clobber(rs_rD1_fr1);
624      Clobber(rs_rD2_fr1);
625      Clobber(rs_rD3_fr1);
626      Clobber(rs_rD4_fr1);
627      Clobber(rs_rD5_fr1);
628      Clobber(rs_rD6_fr1);
629      Clobber(rs_rD7_fr1);
630    }
631  }
632}
633
634RegLocation MipsMir2Lir::GetReturnWideAlt() {
635  UNIMPLEMENTED(FATAL) << "No GetReturnWideAlt for MIPS";
636  RegLocation res = LocCReturnWide();
637  return res;
638}
639
640RegLocation MipsMir2Lir::GetReturnAlt() {
641  UNIMPLEMENTED(FATAL) << "No GetReturnAlt for MIPS";
642  RegLocation res = LocCReturn();
643  return res;
644}
645
646/* To be used when explicitly managing register use */
647void MipsMir2Lir::LockCallTemps() {
648  LockTemp(TargetReg(kArg0));
649  LockTemp(TargetReg(kArg1));
650  LockTemp(TargetReg(kArg2));
651  LockTemp(TargetReg(kArg3));
652  if (cu_->target64) {
653    LockTemp(TargetReg(kArg4));
654    LockTemp(TargetReg(kArg5));
655    LockTemp(TargetReg(kArg6));
656    LockTemp(TargetReg(kArg7));
657  }
658}
659
660/* To be used when explicitly managing register use */
661void MipsMir2Lir::FreeCallTemps() {
662  FreeTemp(TargetReg(kArg0));
663  FreeTemp(TargetReg(kArg1));
664  FreeTemp(TargetReg(kArg2));
665  FreeTemp(TargetReg(kArg3));
666  if (cu_->target64) {
667    FreeTemp(TargetReg(kArg4));
668    FreeTemp(TargetReg(kArg5));
669    FreeTemp(TargetReg(kArg6));
670    FreeTemp(TargetReg(kArg7));
671  }
672  FreeTemp(TargetReg(kHiddenArg));
673}
674
675bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind ATTRIBUTE_UNUSED) {
676  if (cu_->compiler_driver->GetInstructionSetFeatures()->IsSmp()) {
677    NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
678    return true;
679  } else {
680    return false;
681  }
682}
683
684void MipsMir2Lir::CompilerInitializeRegAlloc() {
685  if (cu_->target64) {
686    reg_pool_.reset(new (arena_) RegisterPool(this, arena_, core_regs_64, core_regs_64d, sp_regs_64,
687                                              dp_regs_64, reserved_regs_64, reserved_regs_64d,
688                                              core_temps_64, core_temps_64d, sp_temps_64,
689                                              dp_temps_64));
690
691    // Alias single precision floats to appropriate half of overlapping double.
692    for (RegisterInfo* info : reg_pool_->sp_regs_) {
693      int sp_reg_num = info->GetReg().GetRegNum();
694      int dp_reg_num = sp_reg_num;
695      RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
696      RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
697      // Double precision register's master storage should refer to itself.
698      DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
699      // Redirect single precision's master storage to master.
700      info->SetMaster(dp_reg_info);
701      // Singles should show a single 32-bit mask bit, at first referring to the low half.
702      DCHECK_EQ(info->StorageMask(), 0x1U);
703    }
704
705    // Alias 32bit W registers to corresponding 64bit X registers.
706    for (RegisterInfo* info : reg_pool_->core_regs_) {
707      int d_reg_num = info->GetReg().GetRegNum();
708      RegStorage d_reg = RegStorage::Solo64(d_reg_num);
709      RegisterInfo* d_reg_info = GetRegInfo(d_reg);
710      // 64bit D register's master storage should refer to itself.
711      DCHECK_EQ(d_reg_info, d_reg_info->Master());
712      // Redirect 32bit master storage to 64bit D.
713      info->SetMaster(d_reg_info);
714      // 32bit should show a single 32-bit mask bit, at first referring to the low half.
715      DCHECK_EQ(info->StorageMask(), 0x1U);
716    }
717  } else {
718    reg_pool_.reset(new (arena_) RegisterPool(this, arena_, core_regs_32, empty_pool,  // core64
719                                              sp_regs_32,
720                                              fpuIs32Bit_ ? dp_fr0_regs_32 : dp_fr1_regs_32,
721                                              reserved_regs_32, empty_pool,  // reserved64
722                                              core_temps_32, empty_pool,  // core64_temps
723                                              fpuIs32Bit_ ? sp_fr0_temps_32 : sp_fr1_temps_32,
724                                              fpuIs32Bit_ ? dp_fr0_temps_32 : dp_fr1_temps_32));
725
726    // Alias single precision floats to appropriate half of overlapping double.
727    for (RegisterInfo* info : reg_pool_->sp_regs_) {
728      int sp_reg_num = info->GetReg().GetRegNum();
729      int dp_reg_num = sp_reg_num & ~1;
730      if (fpuIs32Bit_ || (sp_reg_num == dp_reg_num)) {
731        RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
732        RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
733        // Double precision register's master storage should refer to itself.
734        DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
735        // Redirect single precision's master storage to master.
736        info->SetMaster(dp_reg_info);
737        // Singles should show a single 32-bit mask bit, at first referring to the low half.
738        DCHECK_EQ(info->StorageMask(), 0x1U);
739        if (sp_reg_num & 1) {
740          // For odd singles, change to user the high word of the backing double.
741          info->SetStorageMask(0x2);
742        }
743      }
744    }
745  }
746
747  // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
748  // TODO: adjust when we roll to hard float calling convention.
749  reg_pool_->next_core_reg_ = 2;
750  reg_pool_->next_sp_reg_ = 2;
751  if (cu_->target64) {
752    reg_pool_->next_dp_reg_ = 1;
753  } else {
754    reg_pool_->next_dp_reg_ = 2;
755  }
756}
757
758/*
759 * In the Arm code a it is typical to use the link register
760 * to hold the target address.  However, for Mips we must
761 * ensure that all branch instructions can be restarted if
762 * there is a trap in the shadow.  Allocate a temp register.
763 */
764RegStorage MipsMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
765  // NOTE: native pointer.
766  if (cu_->target64) {
767    LoadWordDisp(TargetPtrReg(kSelf), GetThreadOffset<8>(trampoline).Int32Value(),
768                 TargetPtrReg(kInvokeTgt));
769  } else {
770    LoadWordDisp(TargetPtrReg(kSelf), GetThreadOffset<4>(trampoline).Int32Value(),
771                 TargetPtrReg(kInvokeTgt));
772  }
773  return TargetPtrReg(kInvokeTgt);
774}
775
776LIR* MipsMir2Lir::CheckSuspendUsingLoad() {
777  RegStorage tmp = AllocTemp();
778  // NOTE: native pointer.
779  if (cu_->target64) {
780    LoadWordDisp(TargetPtrReg(kSelf), Thread::ThreadSuspendTriggerOffset<8>().Int32Value(), tmp);
781  } else {
782    LoadWordDisp(TargetPtrReg(kSelf), Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
783  }
784  LIR *inst = LoadWordDisp(tmp, 0, tmp);
785  FreeTemp(tmp);
786  return inst;
787}
788
789LIR* MipsMir2Lir::GenAtomic64Load(RegStorage r_base, int displacement, RegStorage r_dest) {
790  DCHECK(!r_dest.IsFloat());  // See RegClassForFieldLoadStore().
791  if (!cu_->target64) {
792    DCHECK(r_dest.IsPair());
793  }
794  ClobberCallerSave();
795  LockCallTemps();  // Using fixed registers.
796  RegStorage reg_ptr = TargetReg(kArg0);
797  OpRegRegImm(kOpAdd, reg_ptr, r_base, displacement);
798  RegStorage r_tgt = LoadHelper(kQuickA64Load);
799  ForceImplicitNullCheck(reg_ptr, 0, true);  // is_wide = true
800  LIR *ret = OpReg(kOpBlx, r_tgt);
801  RegStorage reg_ret;
802  if (cu_->target64) {
803    OpRegCopy(r_dest, TargetReg(kRet0));
804  } else {
805    reg_ret = RegStorage::MakeRegPair(TargetReg(kRet0), TargetReg(kRet1));
806    OpRegCopyWide(r_dest, reg_ret);
807  }
808  return ret;
809}
810
811LIR* MipsMir2Lir::GenAtomic64Store(RegStorage r_base, int displacement, RegStorage r_src) {
812  DCHECK(!r_src.IsFloat());  // See RegClassForFieldLoadStore().
813  if (cu_->target64) {
814    DCHECK(!r_src.IsPair());
815  } else {
816    DCHECK(r_src.IsPair());
817  }
818  ClobberCallerSave();
819  LockCallTemps();  // Using fixed registers.
820  RegStorage temp_ptr = AllocTemp();
821  OpRegRegImm(kOpAdd, temp_ptr, r_base, displacement);
822  ForceImplicitNullCheck(temp_ptr, 0, true);  // is_wide = true
823  RegStorage temp_value = AllocTempWide();
824  OpRegCopyWide(temp_value, r_src);
825  if (cu_->target64) {
826    OpRegCopyWide(TargetReg(kArg0, kWide), temp_ptr);
827    OpRegCopyWide(TargetReg(kArg1, kWide), temp_value);
828  } else {
829    RegStorage reg_ptr = TargetReg(kArg0);
830    OpRegCopy(reg_ptr, temp_ptr);
831    RegStorage reg_value = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
832    OpRegCopyWide(reg_value, temp_value);
833  }
834  FreeTemp(temp_ptr);
835  FreeTemp(temp_value);
836  RegStorage r_tgt = LoadHelper(kQuickA64Store);
837  return OpReg(kOpBlx, r_tgt);
838}
839
840static dwarf::Reg DwarfCoreReg(int num) {
841  return dwarf::Reg::MipsCore(num);
842}
843
844void MipsMir2Lir::SpillCoreRegs() {
845  if (num_core_spills_ == 0) {
846    return;
847  }
848  uint32_t mask = core_spill_mask_;
849  int ptr_size = cu_->target64 ? 8 : 4;
850  int offset = num_core_spills_ * ptr_size;
851  const RegStorage rs_sp = TargetPtrReg(kSp);
852  OpRegImm(kOpSub, rs_sp, offset);
853  cfi_.AdjustCFAOffset(offset);
854  for (int reg = 0; mask; mask >>= 1, reg++) {
855    if (mask & 0x1) {
856      offset -= ptr_size;
857      StoreWordDisp(rs_sp, offset,
858                    cu_->target64 ? RegStorage::Solo64(reg) : RegStorage::Solo32(reg));
859      cfi_.RelOffset(DwarfCoreReg(reg), offset);
860    }
861  }
862}
863
864void MipsMir2Lir::UnSpillCoreRegs() {
865  if (num_core_spills_ == 0) {
866    return;
867  }
868  uint32_t mask = core_spill_mask_;
869  int offset  = frame_size_;
870  int ptr_size = cu_->target64 ? 8 : 4;
871  const RegStorage rs_sp = TargetPtrReg(kSp);
872  for (int reg = 0; mask; mask >>= 1, reg++) {
873    if (mask & 0x1) {
874      offset -= ptr_size;
875      LoadWordDisp(rs_sp, offset,
876                   cu_->target64 ? RegStorage::Solo64(reg) : RegStorage::Solo32(reg));
877      cfi_.Restore(DwarfCoreReg(reg));
878    }
879  }
880  OpRegImm(kOpAdd, rs_sp, frame_size_);
881  cfi_.AdjustCFAOffset(-frame_size_);
882}
883
884bool MipsMir2Lir::IsUnconditionalBranch(LIR* lir) {
885  return (lir->opcode == kMipsB);
886}
887
888RegisterClass MipsMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
889  if (UNLIKELY(is_volatile)) {
890    // On Mips, atomic 64-bit load/store requires a core register.
891    // Smaller aligned load/store is atomic for both core and fp registers.
892    if (size == k64 || size == kDouble) {
893      return kCoreReg;
894    }
895  }
896  // TODO: Verify that both core and fp registers are suitable for smaller sizes.
897  return RegClassBySize(size);
898}
899
900MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
901    : Mir2Lir(cu, mir_graph, arena), in_to_reg_storage_mips64_mapper_(this),
902    in_to_reg_storage_mips_mapper_(this),
903    isaIsR6_(cu_->target64 ? true : cu->compiler_driver->GetInstructionSetFeatures()
904                ->AsMipsInstructionSetFeatures()->IsR6()),
905    fpuIs32Bit_(cu_->target64 ? false : cu->compiler_driver->GetInstructionSetFeatures()
906                   ->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint()) {
907  for (int i = 0; i < kMipsLast; i++) {
908    DCHECK_EQ(MipsMir2Lir::EncodingMap[i].opcode, i)
909        << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
910        << " is wrong: expecting " << i << ", seeing "
911        << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
912  }
913}
914
915Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
916                           ArenaAllocator* const arena) {
917  return new MipsMir2Lir(cu, mir_graph, arena);
918}
919
920uint64_t MipsMir2Lir::GetTargetInstFlags(int opcode) {
921  DCHECK(!IsPseudoLirOp(opcode));
922  return MipsMir2Lir::EncodingMap[opcode].flags;
923}
924
925const char* MipsMir2Lir::GetTargetInstName(int opcode) {
926  DCHECK(!IsPseudoLirOp(opcode));
927  return MipsMir2Lir::EncodingMap[opcode].name;
928}
929
930const char* MipsMir2Lir::GetTargetInstFmt(int opcode) {
931  DCHECK(!IsPseudoLirOp(opcode));
932  return MipsMir2Lir::EncodingMap[opcode].fmt;
933}
934
935}  // namespace art
936