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 
24 namespace art {
25 
26 struct CompilationUnit;
27 
28 class MipsMir2Lir FINAL : public Mir2Lir {
29  protected:
30   class InToRegStorageMipsMapper : public InToRegStorageMapper {
31    public:
InToRegStorageMipsMapper(Mir2Lir * m2l)32     explicit InToRegStorageMipsMapper(Mir2Lir* m2l) : m2l_(m2l), cur_core_reg_(0) {}
33     virtual RegStorage GetNextReg(ShortyArg arg);
Reset()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:
InToRegStorageMips64Mapper(Mir2Lir * m2l)45     explicit InToRegStorageMips64Mapper(Mir2Lir* m2l) : m2l_(m2l), cur_arg_reg_(0) {}
46     virtual RegStorage GetNextReg(ShortyArg arg);
Reset()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_;
GetResetedInToRegStorageMapper()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;
TargetPtrReg(SpecialTargetRegister reg)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 
WideGPRsAreAliases()232   bool WideGPRsAreAliases() const OVERRIDE {
233     return cu_->target64;  // Wide GPRs are formed by pairing on mips32.
234   }
WideFPRsAreAliases()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.
GenInlinedCharAt(CallInfo * info ATTRIBUTE_UNUSED)248   bool GenInlinedCharAt(CallInfo* info ATTRIBUTE_UNUSED) OVERRIDE {
249     return false;
250   }
GenInlinedAbsInt(CallInfo * info ATTRIBUTE_UNUSED)251   bool GenInlinedAbsInt(CallInfo* info ATTRIBUTE_UNUSED) OVERRIDE {
252     return false;
253   }
GenInlinedAbsLong(CallInfo * info ATTRIBUTE_UNUSED)254   bool GenInlinedAbsLong(CallInfo* info ATTRIBUTE_UNUSED) OVERRIDE {
255     return false;
256   }
GenInlinedIndexOf(CallInfo * info ATTRIBUTE_UNUSED,bool zero_based ATTRIBUTE_UNUSED)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    */
As32BitReg(RegStorage reg)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    */
As64BitReg(RegStorage reg)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 
Check64BitReg(RegStorage reg)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