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/ir/inst.h" 21 #include "utils/arena_containers.h" 22 23 namespace panda::compiler { 24 class RegAllocBase; 25 26 /* 27 * There are 3 spill-fill location types: 28 * - general register 29 * - vector register 30 * - stack slot 31 * 32 * Each spill-fill's source and destination is described by index inside these locations; 33 * 34 * Since all destinations are unique, we can use them as keys for table, which collects information about 35 * all moves: 36 * - genenral register index maps to table key one by one 37 * - vector register index offsets on number of genenral registers (MAX_NUM_REGS) 38 * - stack slot index offsets on number of all registers (MAX_NUM_REGS + MAX_NUM_VREGS) 39 * 40 * Iterating over this table `SpillFillsResolver` builds non-conflict chains of spill-fills. 41 * Building process is described before `SpillFillsResolver::Reorder()` method. 42 */ 43 class SpillFillsResolver : public GraphVisitor { 44 static_assert(sizeof(Register) == sizeof(StackSlot), "Register and StackSlot should be the same size"); 45 46 using LocationIndex = uint16_t; 47 static constexpr auto INVALID_LOCATION_INDEX = std::numeric_limits<LocationIndex>::max(); 48 49 struct LocationInfo { 50 LocationType location; 51 LocationIndex idx; 52 }; 53 54 struct MoveInfo { 55 LocationIndex src; 56 DataType::Type reg_type; 57 }; 58 59 public: 60 explicit SpillFillsResolver(Graph *graph); 61 SpillFillsResolver(Graph *graph, Register resolver, size_t regs_count, size_t vregs_count = 0); 62 NO_COPY_SEMANTIC(SpillFillsResolver); 63 NO_MOVE_SEMANTIC(SpillFillsResolver); 64 ~SpillFillsResolver() override = default; 65 66 const ArenaVector<BasicBlock *> &GetBlocksToVisit() const override; 67 68 void Run(); 69 70 void Resolve(SpillFillInst *spill_fill_inst); 71 72 void ResolveIfRequired(SpillFillInst *spill_fill_inst); 73 74 Graph *GetGraph() const; 75 76 protected: 77 static void VisitSpillFill(GraphVisitor *visitor, Inst *inst); 78 79 private: 80 bool NeedToResolve(const ArenaVector<SpillFillData> &spill_fills); 81 void ResolveCallSpillFill(SpillFillInst *spill_fill_inst); 82 void CollectSpillFillsData(SpillFillInst *spill_fill_inst); 83 void Reorder(SpillFillInst *spill_fill_inst); 84 LocationIndex CheckAndResolveCyclicDependency(LocationIndex dst_first); 85 template <bool ciclyc> 86 void AddMovesChain(LocationIndex dst, ArenaVector<LocationIndex> *remap, SpillFillInst *spill_fill_inst); 87 LocationIndex GetResolver(DataType::Type type); 88 89 // Get table index by Location type Map(Location location)90 LocationIndex Map(Location location) 91 { 92 if (location.IsRegister()) { 93 return location.GetValue(); 94 } 95 if (location.IsFpRegister()) { 96 return location.GetValue() + VREGS_TABLE_OFFSET; 97 } 98 if (location.IsStack()) { 99 return location.GetValue() + SLOTS_TABLE_OFFSET; 100 } 101 ASSERT(location.IsStackParameter()); 102 return location.GetValue() + PARAMETER_SLOTS_OFFSET; 103 } 104 105 // Fetch location type and element number inside this location from table index ToLocation(LocationIndex reg)106 Location ToLocation(LocationIndex reg) 107 { 108 if (reg >= PARAMETER_SLOTS_OFFSET) { 109 return Location::MakeStackParameter(reg - PARAMETER_SLOTS_OFFSET); 110 } 111 if (reg >= SLOTS_TABLE_OFFSET) { 112 return Location::MakeStackSlot(reg - SLOTS_TABLE_OFFSET); 113 } 114 if (reg >= VREGS_TABLE_OFFSET) { 115 return Location::MakeFpRegister(reg - VREGS_TABLE_OFFSET); 116 } 117 return Location::MakeRegister(reg); 118 } 119 IsPairedReg(Arch arch,DataType::Type type)120 static inline bool IsPairedReg(Arch arch, DataType::Type type) 121 { 122 return arch != Arch::NONE && !Is64BitsArch(arch) && Is64Bits(type, arch); 123 } 124 125 private: 126 Graph *graph_ {nullptr}; 127 ArenaVector<MoveInfo> moves_table_; 128 ArenaVector<uint8_t> loads_count_; 129 // Group of moves which can be safely inserted before all others 130 ArenaVector<SpillFillData> pre_moves_; 131 // Group of moves which can be safely inserted after all others 132 ArenaVector<SpillFillData> post_moves_; 133 Register resolver_; 134 135 const size_t VREGS_TABLE_OFFSET; 136 const size_t SLOTS_TABLE_OFFSET; 137 const size_t PARAMETER_SLOTS_OFFSET; 138 const size_t LOCATIONS_COUNT; 139 ArenaVector<bool> reg_write_; 140 ArenaVector<bool> stack_write_; 141 142 #include "optimizer/ir/visitor.inc" 143 }; 144 } // namespace panda::compiler 145 146 #endif // COMPILER_OPTIMIZER_OPTIMIZATIONS_REGALLOC_SPILL_FILLS_RESOLVER_H 147