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