• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &regs)
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