• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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_CODEGEN_REGFILE_H
17 #define COMPILER_OPTIMIZER_CODEGEN_REGFILE_H
18 
19 #include "operands.h"
20 #include "utils/arch.h"
21 
22 /*
23 Register file wrapper  used for get major data and for Regalloc
24 */
25 namespace ark::compiler {
26 #ifdef PANDA_COMPILER_TARGET_X86_64
27 namespace amd64 {
28 static constexpr size_t RENAMING_MASK_3_5_OR_9_11 {0xE38};
29 static constexpr size_t RENAMING_CONST {14U};
30 
31 // There is a problem with callee/caller register numbers with amd64.
32 // For example, take a look at
33 // caller reg mask: 0000111111000111 and
34 // callee reg mask: 1111000000001000
35 // Stack walker requires this mask to be densed, so the decision is to
36 // rename regs number 3, 4, 5 to 11, 10, 9 (and vice versa).
37 // Resulting
38 // caller mask is 0000000111111111 and
39 // callee mask is 1111100000000000.
ConvertRegNumber(size_t regId)40 static inline constexpr size_t ConvertRegNumber(size_t regId)
41 {
42     ASSERT(regId < MAX_NUM_REGS);
43     // NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult)
44     if ((RENAMING_MASK_3_5_OR_9_11 & (size_t(1) << regId)) != 0) {
45         return RENAMING_CONST - regId;
46     }
47     return regId;
48 }
49 }  // namespace amd64
50 #endif  // PANDA_COMPILER_TARGET_X86_64
51 
52 class RegistersDescription {
53 public:
RegistersDescription(ArenaAllocator * aa,Arch arch)54     explicit RegistersDescription(ArenaAllocator *aa, Arch arch) : arenaAllocator_(aa), arch_(arch) {}
55     virtual ~RegistersDescription() = default;
56 
57     virtual ArenaVector<Reg> GetCalleeSaved() = 0;
58     virtual void SetCalleeSaved(const ArenaVector<Reg> &) = 0;
59     // Set used regs - change GetCallee
60     virtual void SetUsedRegs(const ArenaVector<Reg> &) = 0;
61     // Return zero register. If target architecture doesn't support zero register, it should return INVALID_REGISTER.
62     virtual Reg GetZeroReg() const = 0;
63     virtual bool IsZeroReg(Reg reg) const = 0;
64     virtual Reg::RegIDType GetTempReg() = 0;
65     virtual Reg::RegIDType GetTempVReg() = 0;
66     // Return RegMapping bitset
67     virtual bool SupportMapping(uint32_t) = 0;
68 
IsValid()69     virtual bool IsValid() const
70     {
71         return false;
72     };
73 
74     virtual bool IsCalleeRegister(Reg reg) = 0;
75 
GetAllocator()76     ArenaAllocator *GetAllocator() const
77     {
78         return arenaAllocator_;
79     };
80 
81     // May be re-define to ignore some cases
IsRegUsed(ArenaVector<Reg> vecReg,Reg reg)82     virtual bool IsRegUsed(ArenaVector<Reg> vecReg, Reg reg)
83     {
84         // size ignored in arm64
85         auto equality = [reg](Reg in) {
86             return ((reg.GetId() == in.GetId()) && (reg.GetType() == in.GetType()) &&
87                     (reg.GetSize() == in.GetSize())) ||
88                    (!reg.IsValid() && !in.IsValid());
89         };
90         return (std::find_if(vecReg.begin(), vecReg.end(), equality) != vecReg.end());
91     }
92 
93     static RegistersDescription *Create(ArenaAllocator *arenaAllocator, Arch arch);
94 
GetRegMask()95     RegMask GetRegMask() const
96     {
97         return regMask_.None() ? GetDefaultRegMask() : regMask_;
98     }
99 
SetRegMask(const RegMask & mask)100     void SetRegMask(const RegMask &mask)
101     {
102         regMask_ = mask;
103     }
104 
105     // Get registers mask which used in codegen, runtime e.t.c
106     // 0 means - available, 1 - unavailable to use
107     // Note that it is a default architecture-specific registers mask.
108     virtual RegMask GetDefaultRegMask() const = 0;
109 
110     // Get vector registers mask which used in codegen, runtime e.t.c
111     virtual VRegMask GetVRegMask() = 0;
112 
113     virtual RegMask GetCallerSavedRegMask() const = 0;
114     virtual RegMask GetCallerSavedVRegMask() const = 0;
115 
116     void FillUsedCalleeSavedRegisters(RegMask *calleeRegs, VRegMask *calleeVregs, bool setAllCalleeRegisters,
117                                       bool irtocOptimized = false)
118     {
119         if (setAllCalleeRegisters) {
120             *calleeRegs = RegMask(ark::GetCalleeRegsMask(arch_, false, irtocOptimized));
121             *calleeVregs = VRegMask(ark::GetCalleeRegsMask(arch_, true, irtocOptimized));
122         } else {
123             ASSERT(!irtocOptimized);
124             *calleeRegs = GetUsedRegsMask<RegMask, false>(GetCalleeSaved());
125             *calleeVregs = GetUsedRegsMask<VRegMask, true>(GetCalleeSaved());
126         }
127     }
128 
129     NO_COPY_SEMANTIC(RegistersDescription);
130     NO_MOVE_SEMANTIC(RegistersDescription);
131 
132 private:
133     ArenaAllocator *arenaAllocator_ {nullptr};
134     Arch arch_;
135     RegMask regMask_ {0};
136 
137     template <typename M, bool IS_FP>
GetUsedRegsMask(const ArenaVector<Reg> & regs)138     M GetUsedRegsMask(const ArenaVector<Reg> &regs)
139     {
140         M mask;
141         for (auto reg : regs) {
142             // NOLINTNEXTLINE(bugprone-branch-clone,-warnings-as-errors)
143             if (reg.IsFloat() && IS_FP) {
144                 mask.set(reg.GetId());
145             } else if (reg.IsScalar() && !IS_FP) {
146                 mask.set(reg.GetId());
147             }
148         }
149         return mask;
150     }
151 };
152 }  // namespace ark::compiler
153 
154 #endif  // COMPILER_OPTIMIZER_CODEGEN_REGFILE_H
155