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> ®s)
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