• 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_CALLCONV_H
17 #define COMPILER_OPTIMIZER_CODEGEN_CALLCONV_H
18 /*
19     Codegen Hi-Level calling-convention interface
20     Also contains branches targets(labels)
21 
22     Responsible for
23         Branches and jump-encoding
24         Labels (points for jump)
25         Conditional instructions
26  */
27 
28 #include "encode.h"
29 #include "compiler/optimizer/ir/datatype.h"
30 #include "compiler/optimizer/ir/locations.h"
31 #include "compiler/optimizer/code_generator/frame_info.h"
32 #include <functional>
33 
34 namespace ark::compiler {
35 class ParameterInfo {
36 public:
37     using SlotID = uint8_t;
38     ParameterInfo() = default;
39     virtual ~ParameterInfo() = default;
40     // Get next native parameter, on condition, what previous list - in vector
41     // Push data in Reg
42     // Return register or stack_slot
43     virtual std::variant<Reg, SlotID> GetNativeParam(const TypeInfo &) = 0;
44 
45     virtual Location GetNextLocation([[maybe_unused]] DataType::Type type) = 0;
46 
Reset()47     void Reset()
48     {
49         currentScalarNumber_ = 0;
50         currentVectorNumber_ = 0;
51         currentStackOffset_ = 0;
52     }
53 
54     NO_COPY_SEMANTIC(ParameterInfo);
55     NO_MOVE_SEMANTIC(ParameterInfo);
56 
57 protected:
58     uint32_t currentScalarNumber_ {0};  // NOLINT(misc-non-private-member-variables-in-classes)
59     uint32_t currentVectorNumber_ {0};  // NOLINT(misc-non-private-member-variables-in-classes)
60     uint8_t currentStackOffset_ {0};    // NOLINT(misc-non-private-member-variables-in-classes)
61 };
62 
63 #ifdef PANDA_COMPILER_DEBUG_INFO
64 struct CfiOffsets {
65     size_t pushFplr {0};
66     size_t setFp {0};
67     size_t pushCallees {0};
68     size_t popCallees {0};
69     size_t popFplr {0};
70 };
71 
72 struct CfiInfo {
73     CfiOffsets offsets;
74     RegMask calleeRegs;
75     VRegMask calleeVregs;
76 };
77 
78 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
79 #define SET_CFI_OFFSET(field, value) GetCfiInfo().offsets.field = value
80 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
81 #define SET_CFI_CALLEE_REGS(value) GetCfiInfo().calleeRegs = value
82 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
83 #define SET_CFI_CALLEE_VREGS(value) GetCfiInfo().calleeVregs = value
84 #else
85 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
86 #define SET_CFI_OFFSET(field, value)
87 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
88 #define SET_CFI_CALLEE_REGS(value)
89 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
90 #define SET_CFI_CALLEE_VREGS(value)
91 #endif
92 
93 /// Specifies CallingConvention mode.
94 class CallConvMode final {
95 public:
CallConvMode(uint32_t value)96     explicit CallConvMode(uint32_t value) : value_(value) {}
97 
98     DEFAULT_COPY_SEMANTIC(CallConvMode);
99     DEFAULT_MOVE_SEMANTIC(CallConvMode);
100 
101     ~CallConvMode() = default;
102 
103 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
104 #define DECLARE_CALLCONV_MODE_MODIFIERS(name) \
105     void Set##name(bool v)                    \
106     {                                         \
107         Flag##name ::Set(v, &value_);         \
108     }                                         \
109     bool Is##name() const                     \
110     {                                         \
111         return Flag##name ::Get(value_);      \
112     }
113 
114 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
115 #define DECLARE_CALLCONV_MODE(name)                    \
116     static CallConvMode name(bool set = true)          \
117     {                                                  \
118         return CallConvMode(Flag##name ::Encode(set)); \
119     }                                                  \
120     DECLARE_CALLCONV_MODE_MODIFIERS(name)
121 
122 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
123 #define DECLARE_CALLCONV_MODE_MODIFIERS(name) \
124     void Set##name(bool v)                    \
125     {                                         \
126         Flag##name ::Set(v, &value_);         \
127     }                                         \
128     bool Is##name() const                     \
129     {                                         \
130         return Flag##name ::Get(value_);      \
131     }
132 
133     // Panda ABI convention (native - otherwise)
134     DECLARE_CALLCONV_MODE(Panda);
135     // Compile for osr (jit - otherwise)
136     DECLARE_CALLCONV_MODE(Osr);
137     // The method from dynamic language
138     DECLARE_CALLCONV_MODE(DynCall);
139     // Use optimized regset for Irtoc code
140     DECLARE_CALLCONV_MODE(OptIrtoc);
141 
142 #undef DECLARE_CALLCONV_MODE
143 #undef DECLARE_CALLCONV_MODIFIERS
144 
145 private:
146     using FlagPanda = BitField<bool, 0, 1>;
147     using FlagOsr = FlagPanda::NextFlag;
148     using FlagDynCall = FlagOsr::NextFlag;
149     using FlagOptIrtoc = FlagDynCall::NextFlag;
150 
151     uint32_t value_ {0};
152 
153     friend CallConvMode operator|(CallConvMode a, CallConvMode b);
154 };
155 
156 inline CallConvMode operator|(CallConvMode a, CallConvMode b)
157 {
158     return CallConvMode(a.value_ | b.value_);
159 }
160 
161 /// Holds specific information about dynamic call mode
162 class CallConvDynInfo {
163 public:
164     // Fixed parameter regs
165     enum : uint8_t {
166         REG_METHOD = 0,
167         REG_NUM_ARGS,
168         REG_COUNT,
169     };
170 
171     // Call frame slots
172     enum : uint8_t {
173         FIXED_SLOT_COUNT = 0,
174         SLOT_CALLEE = FIXED_SLOT_COUNT,
175     };
176 
177     explicit CallConvDynInfo() = default;
178 
CallConvDynInfo(uint32_t numExpectedArgs,uintptr_t expandEntrypointTlsOffset)179     explicit CallConvDynInfo(uint32_t numExpectedArgs, uintptr_t expandEntrypointTlsOffset)
180         : expandEntrypointTlsOffset_(expandEntrypointTlsOffset), numExpectedArgs_(numExpectedArgs), checkRequired_(true)
181     {
182     }
183 
GetExpandEntrypointTlsOffset()184     auto GetExpandEntrypointTlsOffset()
185     {
186         return expandEntrypointTlsOffset_;
187     }
188 
GetNumExpectedArgs()189     auto GetNumExpectedArgs()
190     {
191         return numExpectedArgs_;
192     }
193 
IsCheckRequired()194     auto IsCheckRequired()
195     {
196         return checkRequired_;
197     }
198 
199 private:
200     uintptr_t expandEntrypointTlsOffset_ {0};
201     uint32_t numExpectedArgs_ {0};
202     bool checkRequired_ {false};
203 };
204 
205 /// CallConv - just holds information about calling convention in current architecture.
206 class CallingConvention {
207 public:
208     virtual ~CallingConvention() = default;
209 
210     // All possible reasons for call and return
211     enum Reason {
212         // Reason for save/restore registers
213         FUNCTION,  // Function inside programm
214         NATIVE,    // native function
215         PROGRAMM   // Enter/exit from programm (UNSUPPORTED)
216     };
217 
218     // Implemented in target.cpp
219     static CallingConvention *Create(ArenaAllocator *arenaAllocator, Encoder *enc, RegistersDescription *descr,
220                                      Arch arch, bool isPandaAbi = false, bool isOsr = false, bool isDyn = false,
221                                      bool printAsm = false, bool isOptIrtoc = false);
222 
223 public:
CallingConvention(ArenaAllocator * allocator,Encoder * enc,RegistersDescription * descr,CallConvMode mode)224     CallingConvention(ArenaAllocator *allocator, Encoder *enc, RegistersDescription *descr, CallConvMode mode)
225         : allocator_(allocator), encoder_(enc), regfile_(descr), mode_(mode)
226     {
227     }
228 
GetAllocator()229     ArenaAllocator *GetAllocator() const
230     {
231         return allocator_;
232     }
233 
GetEncoder()234     Encoder *GetEncoder() const
235     {
236         return encoder_;
237     }
238 
SetEncoder(Encoder * enc)239     void SetEncoder(Encoder *enc)
240     {
241         encoder_ = enc;
242     }
243 
GetRegfile()244     RegistersDescription *GetRegfile() const
245     {
246         return regfile_;
247     }
248 
IsValid()249     virtual bool IsValid() const
250     {
251         return false;
252     }
253 
SetDynInfo(CallConvDynInfo dynInfo)254     void SetDynInfo(CallConvDynInfo dynInfo)
255     {
256         dynInfo_ = dynInfo;
257     }
258 
GetDynInfo()259     CallConvDynInfo &GetDynInfo()
260     {
261         return dynInfo_;
262     }
263 
GetMode()264     CallConvMode GetMode() const
265     {
266         return mode_;
267     }
268 
IsPandaMode()269     bool IsPandaMode() const
270     {
271         return mode_.IsPanda();
272     }
273 
IsOsrMode()274     bool IsOsrMode() const
275     {
276         return mode_.IsOsr();
277     }
278 
IsDynCallMode()279     bool IsDynCallMode() const
280     {
281         return mode_.IsDynCall();
282     }
283 
284 #ifdef PANDA_COMPILER_DEBUG_INFO
GetCfiInfo()285     CfiInfo &GetCfiInfo()
286     {
287         return cfiInfo_;
288     }
289 
GetCfiInfo()290     const CfiInfo &GetCfiInfo() const
291     {
292         return cfiInfo_;
293     }
ProvideCFI()294     static constexpr bool ProvideCFI()
295     {
296         return true;
297     }
298 #else
ProvideCFI()299     static constexpr bool ProvideCFI()
300     {
301         return false;
302     }
303 #endif
304 
305     // Prologue/Epilogue interfaces
306     virtual void GeneratePrologue(const FrameInfo &frameInfo) = 0;
307     virtual void GenerateEpilogue(const FrameInfo &frameInfo, std::function<void()> postJob) = 0;
308 
309     virtual void GenerateNativePrologue(const FrameInfo &frameInfo) = 0;
310     virtual void GenerateNativeEpilogue(const FrameInfo &frameInfo, std::function<void()> postJob) = 0;
311 
312     // Code generation completion interfaces
313     virtual void *GetCodeEntry() = 0;
314     virtual uint32_t GetCodeSize() = 0;
315 
316     // Calculating information about parameters and save regs_offset registers for special needs
317     virtual ParameterInfo *GetParameterInfo(uint8_t regsOffset) = 0;
318 
319     NO_COPY_SEMANTIC(CallingConvention);
320     NO_MOVE_SEMANTIC(CallingConvention);
321 
322 private:
323     // Must not use ExecModel!
324     ArenaAllocator *allocator_ {nullptr};
325     Encoder *encoder_ {nullptr};
326     RegistersDescription *regfile_ {nullptr};
327 #ifdef PANDA_COMPILER_DEBUG_INFO
328     CfiInfo cfiInfo_;
329 #endif
330     CallConvDynInfo dynInfo_ {};
331     CallConvMode mode_ {0};
332 };
333 }  // namespace ark::compiler
334 
335 #endif  // COMPILER_OPTIMIZER_CODEGEN_CALLCONV_H
336