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_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 panda::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 reg_id)40 static inline constexpr size_t ConvertRegNumber(size_t reg_id)
41 {
42 ASSERT(reg_id < MAX_NUM_REGS);
43 // NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult)
44 if ((RENAMING_MASK_3_5_OR_9_11 & (size_t(1) << reg_id)) != 0) {
45 return RENAMING_CONST - reg_id;
46 }
47 return reg_id;
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) : arena_allocator_(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 arena_allocator_;
79 };
80
81 // May be re-define to ignore some cases
IsRegUsed(ArenaVector<Reg> vec_reg,Reg reg)82 virtual bool IsRegUsed(ArenaVector<Reg> vec_reg, 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(vec_reg.begin(), vec_reg.end(), equality) != vec_reg.end());
91 }
92
93 static RegistersDescription *Create(ArenaAllocator *arena_allocator, Arch arch);
94
GetRegMask()95 RegMask GetRegMask() const
96 {
97 return reg_mask_.None() ? GetDefaultRegMask() : reg_mask_;
98 }
99
SetRegMask(const RegMask & mask)100 void SetRegMask(const RegMask &mask)
101 {
102 reg_mask_ = 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
FillUsedCalleeSavedRegisters(RegMask * callee_regs,VRegMask * callee_vregs,bool set_all_callee_registers)116 void FillUsedCalleeSavedRegisters(RegMask *callee_regs, VRegMask *callee_vregs, bool set_all_callee_registers)
117 {
118 if (set_all_callee_registers) {
119 *callee_regs = RegMask(panda::GetCalleeRegsMask(arch_, false));
120 *callee_vregs = VRegMask(panda::GetCalleeRegsMask(arch_, true));
121 } else {
122 *callee_regs = GetUsedRegsMask<RegMask, false>(GetCalleeSaved());
123 *callee_vregs = GetUsedRegsMask<VRegMask, true>(GetCalleeSaved());
124 }
125 }
126
127 NO_COPY_SEMANTIC(RegistersDescription);
128 NO_MOVE_SEMANTIC(RegistersDescription);
129
130 private:
131 ArenaAllocator *arena_allocator_ {nullptr};
132 Arch arch_;
133 RegMask reg_mask_ {0};
134
135 template <typename M, bool is_fp>
GetUsedRegsMask(const ArenaVector<Reg> & regs)136 M GetUsedRegsMask(const ArenaVector<Reg> ®s)
137 {
138 M mask;
139 for (auto reg : regs) {
140 // NOLINTNEXTLINE(bugprone-branch-clone,-warnings-as-errors)
141 if (reg.IsFloat() && is_fp) {
142 mask.set(reg.GetId());
143 } else if (reg.IsScalar() && !is_fp) {
144 mask.set(reg.GetId());
145 }
146 }
147 return mask;
148 }
149 };
150 } // namespace panda::compiler
151
152 #endif // COMPILER_OPTIMIZER_CODEGEN_REGFILE_H_
153