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#ifndef ART_COMPILER_DEX_QUICK_MIPS_CODEGEN_MIPS_H_
18#define ART_COMPILER_DEX_QUICK_MIPS_CODEGEN_MIPS_H_
19
20#include "dex/compiler_ir.h"
21#include "dex/quick/mir_to_lir.h"
22#include "mips_lir.h"
23
24namespace art {
25
26struct CompilationUnit;
27
28class MipsMir2Lir FINAL : public Mir2Lir {
29 protected:
30  class InToRegStorageMipsMapper : public InToRegStorageMapper {
31   public:
32    explicit InToRegStorageMipsMapper(Mir2Lir* m2l) : m2l_(m2l), cur_core_reg_(0) {}
33    virtual RegStorage GetNextReg(ShortyArg arg);
34    virtual void Reset() OVERRIDE {
35      cur_core_reg_ = 0;
36    }
37   protected:
38    Mir2Lir* m2l_;
39   private:
40    size_t cur_core_reg_;
41  };
42
43  class InToRegStorageMips64Mapper : public InToRegStorageMapper {
44   public:
45    explicit InToRegStorageMips64Mapper(Mir2Lir* m2l) : m2l_(m2l), cur_arg_reg_(0) {}
46    virtual RegStorage GetNextReg(ShortyArg arg);
47    virtual void Reset() OVERRIDE {
48      cur_arg_reg_ = 0;
49    }
50   protected:
51    Mir2Lir* m2l_;
52   private:
53    size_t cur_arg_reg_;
54  };
55
56  InToRegStorageMips64Mapper in_to_reg_storage_mips64_mapper_;
57  InToRegStorageMipsMapper in_to_reg_storage_mips_mapper_;
58  InToRegStorageMapper* GetResetedInToRegStorageMapper() OVERRIDE {
59    InToRegStorageMapper* res;
60    if (cu_->target64) {
61      res = &in_to_reg_storage_mips64_mapper_;
62    } else {
63      res = &in_to_reg_storage_mips_mapper_;
64    }
65    res->Reset();
66    return res;
67  }
68
69 public:
70  MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
71
72  // Required for target - codegen utilities.
73  bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
74                          RegLocation rl_dest, int lit);
75  bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE;
76  void GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1, int32_t constant)
77  OVERRIDE;
78  void GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1, int64_t constant)
79  OVERRIDE;
80  LIR* CheckSuspendUsingLoad() OVERRIDE;
81  RegStorage LoadHelper(QuickEntrypointEnum trampoline) OVERRIDE;
82  void ForceImplicitNullCheck(RegStorage reg, int opt_flags, bool is_wide);
83  LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size,
84                    VolatileKind is_volatile) OVERRIDE;
85  LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, int scale,
86                       OpSize size) OVERRIDE;
87  LIR* LoadConstantNoClobber(RegStorage r_dest, int value);
88  LIR* LoadConstantWideNoClobber(RegStorage r_dest, int64_t value);
89  LIR* LoadConstantWide(RegStorage r_dest, int64_t value);
90  LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, OpSize size,
91                     VolatileKind is_volatile) OVERRIDE;
92  LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, int scale,
93                        OpSize size) OVERRIDE;
94  LIR* GenAtomic64Load(RegStorage r_base, int displacement, RegStorage r_dest);
95  LIR* GenAtomic64Store(RegStorage r_base, int displacement, RegStorage r_src);
96
97  /// @copydoc Mir2Lir::UnconditionallyMarkGCCard(RegStorage)
98  void UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) OVERRIDE;
99
100  // Required for target - register utilities.
101  RegStorage Solo64ToPair64(RegStorage reg);
102  RegStorage Fp64ToSolo32(RegStorage reg);
103  RegStorage TargetReg(SpecialTargetRegister reg);
104  RegStorage TargetReg(SpecialTargetRegister reg, WideKind wide_kind) OVERRIDE;
105  RegStorage TargetPtrReg(SpecialTargetRegister reg) OVERRIDE {
106    return TargetReg(reg, cu_->target64 ? kWide : kNotWide);
107  }
108  RegLocation GetReturnAlt();
109  RegLocation GetReturnWideAlt();
110  RegLocation LocCReturn();
111  RegLocation LocCReturnRef();
112  RegLocation LocCReturnDouble();
113  RegLocation LocCReturnFloat();
114  RegLocation LocCReturnWide();
115  ResourceMask GetRegMaskCommon(const RegStorage& reg) const OVERRIDE;
116  void AdjustSpillMask();
117  void ClobberCallerSave();
118  void FreeCallTemps();
119  void LockCallTemps();
120  void CompilerInitializeRegAlloc();
121
122  // Required for target - miscellaneous.
123  void AssembleLIR();
124  int AssignInsnOffsets();
125  void AssignOffsets();
126  AssemblerStatus AssembleInstructions(CodeOffset start_addr);
127  void DumpResourceMask(LIR* lir, const ResourceMask& mask, const char* prefix) OVERRIDE;
128  void SetupTargetResourceMasks(LIR* lir, uint64_t flags, ResourceMask* use_mask,
129                                ResourceMask* def_mask) OVERRIDE;
130  const char* GetTargetInstFmt(int opcode);
131  const char* GetTargetInstName(int opcode);
132  std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
133  ResourceMask GetPCUseDefEncoding() const OVERRIDE;
134  uint64_t GetTargetInstFlags(int opcode);
135  size_t GetInsnSize(LIR* lir) OVERRIDE;
136  bool IsUnconditionalBranch(LIR* lir);
137
138  // Get the register class for load/store of a field.
139  RegisterClass RegClassForFieldLoadStore(OpSize size, bool is_volatile) OVERRIDE;
140
141  // Required for target - Dalvik-level generators.
142  void GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
143                      RegLocation lr_shift);
144  void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
145                         RegLocation rl_src2, int flags);
146  void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array, RegLocation rl_index,
147                   RegLocation rl_dest, int scale);
148  void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array, RegLocation rl_index,
149                   RegLocation rl_src, int scale, bool card_mark);
150  void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
151                         RegLocation rl_shift, int flags);
152  void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
153                        RegLocation rl_src2);
154  void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
155                       RegLocation rl_src2);
156  void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
157                RegLocation rl_src2);
158  void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
159  bool GenInlinedAbsFloat(CallInfo* info) OVERRIDE;
160  bool GenInlinedAbsDouble(CallInfo* info) OVERRIDE;
161  bool GenInlinedCas(CallInfo* info, bool is_long, bool is_object);
162  bool GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long);
163  bool GenInlinedSqrt(CallInfo* info);
164  bool GenInlinedPeek(CallInfo* info, OpSize size);
165  bool GenInlinedPoke(CallInfo* info, OpSize size);
166  void GenIntToLong(RegLocation rl_dest, RegLocation rl_src) OVERRIDE;
167  void GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
168                      RegLocation rl_src2, int flags) OVERRIDE;
169  RegLocation GenDivRem(RegLocation rl_dest, RegStorage reg_lo, RegStorage reg_hi, bool is_div);
170  RegLocation GenDivRemLit(RegLocation rl_dest, RegStorage reg_lo, int lit, bool is_div);
171  void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
172  void GenDivZeroCheckWide(RegStorage reg);
173  void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
174  void GenExitSequence();
175  void GenSpecialExitSequence() OVERRIDE;
176  void GenSpecialEntryForSuspend() OVERRIDE;
177  void GenSpecialExitForSuspend() OVERRIDE;
178  void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
179  void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
180  void GenSelect(BasicBlock* bb, MIR* mir);
181  void GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
182                        int32_t true_val, int32_t false_val, RegStorage rs_dest,
183                        RegisterClass dest_reg_class) OVERRIDE;
184  bool GenMemBarrier(MemBarrierKind barrier_kind);
185  void GenMoveException(RegLocation rl_dest);
186  void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
187                                     int first_bit, int second_bit);
188  void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
189  void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
190  void GenLargePackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
191  void GenLargeSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
192  bool GenSpecialCase(BasicBlock* bb, MIR* mir, const InlineMethod& special);
193
194  // Required for target - single operation generators.
195  LIR* OpUnconditionalBranch(LIR* target);
196  LIR* OpCmpBranch(ConditionCode cond, RegStorage src1, RegStorage src2, LIR* target);
197  LIR* OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value, LIR* target);
198  LIR* OpCondBranch(ConditionCode cc, LIR* target);
199  LIR* OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target);
200  LIR* OpFpRegCopy(RegStorage r_dest, RegStorage r_src);
201  LIR* OpIT(ConditionCode cond, const char* guide);
202  void OpEndIT(LIR* it);
203  LIR* OpMem(OpKind op, RegStorage r_base, int disp);
204  void OpPcRelLoad(RegStorage reg, LIR* target);
205  LIR* OpReg(OpKind op, RegStorage r_dest_src);
206  void OpRegCopy(RegStorage r_dest, RegStorage r_src);
207  LIR* OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src);
208  LIR* OpRegImm(OpKind op, RegStorage r_dest_src1, int value);
209  LIR* OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2);
210  LIR* OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset, MoveType move_type);
211  LIR* OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src, MoveType move_type);
212  LIR* OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, RegStorage r_src);
213  LIR* OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value);
214  LIR* OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2);
215  LIR* OpTestSuspend(LIR* target);
216  LIR* OpVldm(RegStorage r_base, int count);
217  LIR* OpVstm(RegStorage r_base, int count);
218  void OpRegCopyWide(RegStorage dest, RegStorage src);
219
220  // TODO: collapse r_dest.
221  LIR* LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size);
222  // TODO: collapse r_src.
223  LIR* StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src, OpSize size);
224  void SpillCoreRegs();
225  void UnSpillCoreRegs();
226  static const MipsEncodingMap EncodingMap[kMipsLast];
227  bool InexpensiveConstantInt(int32_t value);
228  bool InexpensiveConstantFloat(int32_t value);
229  bool InexpensiveConstantLong(int64_t value);
230  bool InexpensiveConstantDouble(int64_t value);
231
232  bool WideGPRsAreAliases() const OVERRIDE {
233    return cu_->target64;  // Wide GPRs are formed by pairing on mips32.
234  }
235  bool WideFPRsAreAliases() const OVERRIDE {
236    return cu_->target64;  // Wide FPRs are formed by pairing on mips32.
237  }
238
239  LIR* InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) OVERRIDE;
240
241  RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2, bool is_div,
242                        int flags) OVERRIDE;
243  RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) OVERRIDE;
244  NextCallInsn GetNextSDCallInsn() OVERRIDE;
245  LIR* GenCallInsn(const MirMethodLoweringInfo& method_info) OVERRIDE;
246
247  // Unimplemented intrinsics.
248  bool GenInlinedCharAt(CallInfo* info ATTRIBUTE_UNUSED) OVERRIDE {
249    return false;
250  }
251  bool GenInlinedAbsInt(CallInfo* info ATTRIBUTE_UNUSED) OVERRIDE {
252    return false;
253  }
254  bool GenInlinedAbsLong(CallInfo* info ATTRIBUTE_UNUSED) OVERRIDE {
255    return false;
256  }
257  bool GenInlinedIndexOf(CallInfo* info ATTRIBUTE_UNUSED, bool zero_based ATTRIBUTE_UNUSED)
258  OVERRIDE {
259    return false;
260  }
261
262  // True if isa is rev R6.
263  const bool isaIsR6_;
264
265  // True if floating point unit is 32bits.
266  const bool fpuIs32Bit_;
267
268 private:
269  void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
270  void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
271  void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
272
273  void ConvertShortToLongBranch(LIR* lir);
274
275  // Mips64 specific long gen methods:
276  void GenLongOp(OpKind op, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
277  void GenNotLong(RegLocation rl_dest, RegLocation rl_src);
278  void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
279  void GenDivRemLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
280                     RegLocation rl_src2, bool is_div, int flags);
281  void GenConversionCall(QuickEntrypointEnum trampoline, RegLocation rl_dest, RegLocation rl_src,
282                         RegisterClass reg_class);
283  RegStorage AllocPtrSizeTemp(bool required = true);
284
285  /**
286   * @param reg #RegStorage containing a Solo64 input register (e.g. @c a1 or @c d0).
287   * @return A Solo32 with the same register number as the @p reg (e.g. @c a1 or @c f0).
288   * @see As64BitReg
289   */
290  RegStorage As32BitReg(RegStorage reg) {
291    DCHECK(!reg.IsPair());
292    if ((kFailOnSizeError || kReportSizeError) && !reg.Is64Bit()) {
293      if (kFailOnSizeError) {
294        LOG(FATAL) << "Expected 64b register";
295      } else {
296        LOG(WARNING) << "Expected 64b register";
297        return reg;
298      }
299    }
300    RegStorage ret_val = RegStorage(RegStorage::k32BitSolo,
301                                    reg.GetRawBits() & RegStorage::kRegTypeMask);
302    DCHECK_EQ(GetRegInfo(reg)->FindMatchingView(RegisterInfo::k32SoloStorageMask)
303              ->GetReg().GetReg(),
304              ret_val.GetReg());
305    return ret_val;
306  }
307
308  /**
309   * @param reg #RegStorage containing a Solo32 input register (e.g. @c a1 or @c f0).
310   * @return A Solo64 with the same register number as the @p reg (e.g. @c a1 or @c d0).
311   */
312  RegStorage As64BitReg(RegStorage reg) {
313    DCHECK(!reg.IsPair());
314    if ((kFailOnSizeError || kReportSizeError) && !reg.Is32Bit()) {
315      if (kFailOnSizeError) {
316        LOG(FATAL) << "Expected 32b register";
317      } else {
318        LOG(WARNING) << "Expected 32b register";
319        return reg;
320      }
321    }
322    RegStorage ret_val = RegStorage(RegStorage::k64BitSolo,
323                                    reg.GetRawBits() & RegStorage::kRegTypeMask);
324    DCHECK_EQ(GetRegInfo(reg)->FindMatchingView(RegisterInfo::k64SoloStorageMask)
325              ->GetReg().GetReg(),
326              ret_val.GetReg());
327    return ret_val;
328  }
329
330  RegStorage Check64BitReg(RegStorage reg) {
331    if ((kFailOnSizeError || kReportSizeError) && !reg.Is64Bit()) {
332      if (kFailOnSizeError) {
333        LOG(FATAL) << "Checked for 64b register";
334      } else {
335        LOG(WARNING) << "Checked for 64b register";
336        return As64BitReg(reg);
337      }
338    }
339    return reg;
340  }
341};
342
343}  // namespace art
344
345#endif  // ART_COMPILER_DEX_QUICK_MIPS_CODEGEN_MIPS_H_
346