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