1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef COMPILER_OPTIMIZER_OPTIMIZATIONS_REGALLOC_SPILL_FILLS_RESOLVER_H 17 #define COMPILER_OPTIMIZER_OPTIMIZATIONS_REGALLOC_SPILL_FILLS_RESOLVER_H 18 19 #include "compiler/optimizer/ir/graph_visitor.h" 20 #include "optimizer/code_generator/registers_description.h" 21 #include "optimizer/ir/inst.h" 22 #include "utils/arena_containers.h" 23 24 namespace panda::compiler { 25 class RegAllocBase; 26 27 /* 28 * There are 3 spill-fill location types: 29 * - general register 30 * - vector register 31 * - stack slot 32 * 33 * Each spill-fill's source and destination is described by index inside these locations; 34 * 35 * Since all destinations are unique, we can use them as keys for table, which collects information about 36 * all moves: 37 * - genenral register index maps to table key one by one 38 * - vector register index offsets on number of genenral registers (MAX_NUM_REGS) 39 * - stack slot index offsets on number of all registers (MAX_NUM_REGS + MAX_NUM_VREGS) 40 * 41 * Iterating over this table `SpillFillsResolver` builds non-conflict chains of spill-fills. 42 * Building process is described before `SpillFillsResolver::Reorder()` method. 43 */ 44 class SpillFillsResolver : public GraphVisitor { 45 static_assert(sizeof(Register) == sizeof(StackSlot), "Register and StackSlot should be the same size"); 46 47 using LocationIndex = uint16_t; 48 static constexpr auto INVALID_LOCATION_INDEX = std::numeric_limits<LocationIndex>::max(); 49 50 struct LocationInfo { 51 LocationType location; 52 LocationIndex idx; 53 }; 54 55 struct MoveInfo { 56 LocationIndex src; 57 DataType::Type reg_type; 58 }; 59 60 public: 61 explicit SpillFillsResolver(Graph *graph); 62 SpillFillsResolver(Graph *graph, Register resolver, size_t regs_count, size_t vregs_count = 0); 63 NO_COPY_SEMANTIC(SpillFillsResolver); 64 NO_MOVE_SEMANTIC(SpillFillsResolver); 65 ~SpillFillsResolver() override = default; 66 67 const ArenaVector<BasicBlock *> &GetBlocksToVisit() const override; 68 69 void Run(); 70 71 void Resolve(SpillFillInst *spill_fill_inst); 72 73 void ResolveIfRequired(SpillFillInst *spill_fill_inst); 74 75 Graph *GetGraph() const; 76 77 protected: 78 static void VisitSpillFill(GraphVisitor *v, Inst *inst); 79 80 private: 81 bool NeedToResolve(const ArenaVector<SpillFillData> &spill_fills); 82 void ResolveCallSpillFill(SpillFillInst *spill_fill_inst); 83 void CollectSpillFillsData(SpillFillInst *spill_fill_inst); 84 void Reorder(SpillFillInst *spill_fill_inst); 85 LocationIndex CheckAndResolveCyclicDependency(LocationIndex dst_first); 86 template <bool ciclyc> 87 void AddMovesChain(LocationIndex dst, ArenaVector<LocationIndex> *remap, SpillFillInst *spill_fill_inst); 88 LocationIndex GetResolver(DataType::Type type); 89 90 // Get table index by Location type Map(Location location)91 LocationIndex Map(Location location) 92 { 93 if (location.IsRegister()) { 94 return location.GetValue(); 95 } 96 if (location.IsFpRegister()) { 97 return location.GetValue() + VREGS_TABLE_OFFSET; 98 } 99 if (location.IsStack()) { 100 return location.GetValue() + SLOTS_TABLE_OFFSET; 101 } 102 ASSERT(location.IsStackParameter()); 103 return location.GetValue() + PARAMETER_SLOTS_OFFSET; 104 } 105 106 // Fetch location type and element number inside this location from table index ToLocation(LocationIndex reg)107 Location ToLocation(LocationIndex reg) 108 { 109 if (reg >= PARAMETER_SLOTS_OFFSET) { 110 return Location::MakeStackParameter(reg - PARAMETER_SLOTS_OFFSET); 111 } 112 if (reg >= SLOTS_TABLE_OFFSET) { 113 return Location::MakeStackSlot(reg - SLOTS_TABLE_OFFSET); 114 } 115 if (reg >= VREGS_TABLE_OFFSET) { 116 return Location::MakeFpRegister(reg - VREGS_TABLE_OFFSET); 117 } 118 return Location::MakeRegister(reg); 119 } 120 IsPairedReg(Arch arch,DataType::Type type)121 static inline bool IsPairedReg(Arch arch, DataType::Type type) 122 { 123 return arch != Arch::NONE && !Is64BitsArch(arch) && Is64Bits(type, arch); 124 } 125 126 private: 127 Graph *graph_ {nullptr}; 128 ArenaVector<MoveInfo> moves_table_; 129 ArenaVector<uint8_t> loads_count_; 130 // Group of moves which can be safely inserted before all others 131 ArenaVector<SpillFillData> pre_moves_; 132 // Group of moves which can be safely inserted after all others 133 ArenaVector<SpillFillData> post_moves_; 134 Register resolver_; 135 136 const size_t VREGS_TABLE_OFFSET; 137 const size_t SLOTS_TABLE_OFFSET; 138 const size_t PARAMETER_SLOTS_OFFSET; 139 const size_t LOCATIONS_COUNT; 140 ArenaVector<bool> reg_write_; 141 ArenaVector<bool> stack_write_; 142 143 #include "optimizer/ir/visitor.inc" 144 }; 145 } // namespace panda::compiler 146 147 #endif // COMPILER_OPTIMIZER_OPTIMIZATIONS_REGALLOC_SPILL_FILLS_RESOLVER_H 148