• 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         /* CC-OFFNXT(G.PRE.05) function gen */ \
112         return Flag##name ::Get(value_);       \
113     }
114 
115 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
116 #define DECLARE_CALLCONV_MODE(name)                    \
117     static CallConvMode name(bool set = true)          \
118     {                                                  \
119         /* CC-OFFNXT(G.PRE.05) function gen */         \
120         return CallConvMode(Flag##name ::Encode(set)); \
121     }                                                  \
122     DECLARE_CALLCONV_MODE_MODIFIERS(name)
123 
124 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
125 #define DECLARE_CALLCONV_MODE_MODIFIERS(name)  \
126     void Set##name(bool v)                     \
127     {                                          \
128         Flag##name ::Set(v, &value_);          \
129     }                                          \
130     bool Is##name() const                      \
131     {                                          \
132         /* CC-OFFNXT(G.PRE.05) function gen */ \
133         return Flag##name ::Get(value_);       \
134     }
135 
136     // Panda ABI convention (native - otherwise)
137     DECLARE_CALLCONV_MODE(Panda);
138     // Compile for osr (jit - otherwise)
139     DECLARE_CALLCONV_MODE(Osr);
140     // The method from dynamic language
141     DECLARE_CALLCONV_MODE(DynCall);
142     // Use optimized regset for Irtoc code
143     DECLARE_CALLCONV_MODE(OptIrtoc);
144 
145 #undef DECLARE_CALLCONV_MODE
146 #undef DECLARE_CALLCONV_MODIFIERS
147 
148 private:
149     using FlagPanda = BitField<bool, 0, 1>;
150     using FlagOsr = FlagPanda::NextFlag;
151     using FlagDynCall = FlagOsr::NextFlag;
152     using FlagOptIrtoc = FlagDynCall::NextFlag;
153 
154     uint32_t value_ {0};
155 
156     friend CallConvMode operator|(CallConvMode a, CallConvMode b);
157 };
158 
159 inline CallConvMode operator|(CallConvMode a, CallConvMode b)
160 {
161     return CallConvMode(a.value_ | b.value_);
162 }
163 
164 /// Holds specific information about dynamic call mode
165 class CallConvDynInfo {
166 public:
167     // Fixed parameter regs
168     enum : uint8_t {
169         REG_METHOD = 0,
170         REG_NUM_ARGS,
171         REG_COUNT,
172     };
173 
174     // Call frame slots
175     enum : uint8_t {
176         FIXED_SLOT_COUNT = 0,
177         SLOT_CALLEE = FIXED_SLOT_COUNT,
178     };
179 
180     explicit CallConvDynInfo() = default;
181 
CallConvDynInfo(uint32_t numExpectedArgs,uintptr_t expandEntrypointTlsOffset)182     explicit CallConvDynInfo(uint32_t numExpectedArgs, uintptr_t expandEntrypointTlsOffset)
183         : expandEntrypointTlsOffset_(expandEntrypointTlsOffset), numExpectedArgs_(numExpectedArgs), checkRequired_(true)
184     {
185     }
186 
GetExpandEntrypointTlsOffset()187     auto GetExpandEntrypointTlsOffset()
188     {
189         return expandEntrypointTlsOffset_;
190     }
191 
GetNumExpectedArgs()192     auto GetNumExpectedArgs()
193     {
194         return numExpectedArgs_;
195     }
196 
IsCheckRequired()197     auto IsCheckRequired()
198     {
199         return checkRequired_;
200     }
201 
202 private:
203     uintptr_t expandEntrypointTlsOffset_ {0};
204     uint32_t numExpectedArgs_ {0};
205     bool checkRequired_ {false};
206 };
207 
208 /// CallConv - just holds information about calling convention in current architecture.
209 class CallingConvention {
210 public:
211     virtual ~CallingConvention() = default;
212 
213     // All possible reasons for call and return
214     enum Reason {
215         // Reason for save/restore registers
216         FUNCTION,  // Function inside programm
217         NATIVE,    // native function
218         PROGRAMM   // Enter/exit from programm (UNSUPPORTED)
219     };
220 
221     // Implemented in target.cpp
222     static CallingConvention *Create(ArenaAllocator *arenaAllocator, Encoder *enc, RegistersDescription *descr,
223                                      Arch arch, bool isPandaAbi = false, bool isOsr = false, bool isDyn = false,
224                                      bool printAsm = false, bool isOptIrtoc = false);
225 
226 public:
CallingConvention(ArenaAllocator * allocator,Encoder * enc,RegistersDescription * descr,CallConvMode mode)227     CallingConvention(ArenaAllocator *allocator, Encoder *enc, RegistersDescription *descr, CallConvMode mode)
228         : allocator_(allocator), encoder_(enc), regfile_(descr), mode_(mode)
229     {
230     }
231 
GetAllocator()232     ArenaAllocator *GetAllocator() const
233     {
234         return allocator_;
235     }
236 
GetEncoder()237     Encoder *GetEncoder() const
238     {
239         return encoder_;
240     }
241 
SetEncoder(Encoder * enc)242     void SetEncoder(Encoder *enc)
243     {
244         encoder_ = enc;
245     }
246 
GetRegfile()247     RegistersDescription *GetRegfile() const
248     {
249         return regfile_;
250     }
251 
IsValid()252     virtual bool IsValid() const
253     {
254         return false;
255     }
256 
SetDynInfo(CallConvDynInfo dynInfo)257     void SetDynInfo(CallConvDynInfo dynInfo)
258     {
259         dynInfo_ = dynInfo;
260     }
261 
GetDynInfo()262     CallConvDynInfo &GetDynInfo()
263     {
264         return dynInfo_;
265     }
266 
GetMode()267     CallConvMode GetMode() const
268     {
269         return mode_;
270     }
271 
IsPandaMode()272     bool IsPandaMode() const
273     {
274         return mode_.IsPanda();
275     }
276 
IsOsrMode()277     bool IsOsrMode() const
278     {
279         return mode_.IsOsr();
280     }
281 
IsDynCallMode()282     bool IsDynCallMode() const
283     {
284         return mode_.IsDynCall();
285     }
286 
287 #ifdef PANDA_COMPILER_DEBUG_INFO
GetCfiInfo()288     CfiInfo &GetCfiInfo()
289     {
290         return cfiInfo_;
291     }
292 
GetCfiInfo()293     const CfiInfo &GetCfiInfo() const
294     {
295         return cfiInfo_;
296     }
ProvideCFI()297     static constexpr bool ProvideCFI()
298     {
299         return true;
300     }
301 #else
ProvideCFI()302     static constexpr bool ProvideCFI()
303     {
304         return false;
305     }
306 #endif
307 
308     // Prologue/Epilogue interfaces
309     virtual void GeneratePrologue(const FrameInfo &frameInfo) = 0;
310     virtual void GenerateEpilogue(const FrameInfo &frameInfo, std::function<void()> postJob) = 0;
311 
312     virtual void GenerateNativePrologue(const FrameInfo &frameInfo) = 0;
313     virtual void GenerateNativeEpilogue(const FrameInfo &frameInfo, std::function<void()> postJob) = 0;
314 
315     // Code generation completion interfaces
316     virtual void *GetCodeEntry() = 0;
317     virtual uint32_t GetCodeSize() = 0;
318 
319     // Calculating information about parameters and save regs_offset registers for special needs
320     virtual ParameterInfo *GetParameterInfo(uint8_t regsOffset) = 0;
321 
322     NO_COPY_SEMANTIC(CallingConvention);
323     NO_MOVE_SEMANTIC(CallingConvention);
324 
325 private:
326     // Must not use ExecModel!
327     ArenaAllocator *allocator_ {nullptr};
328     Encoder *encoder_ {nullptr};
329     RegistersDescription *regfile_ {nullptr};
330 #ifdef PANDA_COMPILER_DEBUG_INFO
331     CfiInfo cfiInfo_;
332 #endif
333     CallConvDynInfo dynInfo_ {};
334     CallConvMode mode_ {0};
335 };
336 }  // namespace ark::compiler
337 
338 #endif  // COMPILER_OPTIMIZER_CODEGEN_CALLCONV_H
339