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_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 <functional> 29 #include "encode.h" 30 #include "compiler/optimizer/ir/datatype.h" 31 #include "compiler/optimizer/ir/locations.h" 32 #include "compiler/optimizer/code_generator/frame_info.h" 33 34 namespace panda::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 current_scalar_number_ = 0; 50 current_vector_number_ = 0; 51 current_stack_offset_ = 0; 52 } 53 54 NO_COPY_SEMANTIC(ParameterInfo); 55 NO_MOVE_SEMANTIC(ParameterInfo); 56 57 protected: 58 uint32_t current_scalar_number_ {0}; // NOLINT(misc-non-private-member-variables-in-classes) 59 uint32_t current_vector_number_ {0}; // NOLINT(misc-non-private-member-variables-in-classes) 60 uint8_t current_stack_offset_ {0}; // NOLINT(misc-non-private-member-variables-in-classes) 61 }; 62 63 #ifdef PANDA_COMPILER_CFI 64 struct CfiOffsets { 65 size_t push_fplr {0}; 66 size_t set_fp {0}; 67 size_t push_callees {0}; 68 size_t pop_callees {0}; 69 size_t pop_fplr {0}; 70 }; 71 72 struct CfiInfo { 73 CfiOffsets offsets; 74 RegMask callee_regs; 75 VRegMask callee_vregs; 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().callee_regs = value 82 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 83 #define SET_CFI_CALLEE_VREGS(value) GetCfiInfo().callee_vregs = 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 /** 94 * Specifies CallingConvention mode. 95 */ 96 class CallConvMode final { 97 public: CallConvMode(uint32_t value)98 explicit CallConvMode(uint32_t value) : value_(value) {} 99 100 DEFAULT_COPY_SEMANTIC(CallConvMode); 101 DEFAULT_MOVE_SEMANTIC(CallConvMode); 102 103 ~CallConvMode() = default; 104 105 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 106 #define DECLARE_CALLCONV_MODE(name) \ 107 static CallConvMode name(bool set = true) \ 108 { \ 109 return CallConvMode(Flag##name ::Encode(set)); \ 110 } \ 111 void Set##name(bool v) \ 112 { \ 113 Flag##name ::Set(v, &value_); \ 114 } \ 115 bool Is##name() const \ 116 { \ 117 return Flag##name ::Get(value_); \ 118 } 119 120 // Panda ABI convention (native - otherwise) 121 DECLARE_CALLCONV_MODE(Panda); 122 // Compile for osr (jit - otherwise) 123 DECLARE_CALLCONV_MODE(Osr); 124 // The method from dynamic language 125 DECLARE_CALLCONV_MODE(Dyn); 126 127 #undef DECLARE_CALLCONV_MODE 128 129 private: 130 using FlagPanda = BitField<bool, 0, 1>; 131 using FlagOsr = FlagPanda::NextFlag; 132 using FlagDyn = FlagOsr::NextFlag; 133 134 uint32_t value_ {0}; 135 136 friend CallConvMode operator|(CallConvMode a, CallConvMode b); 137 }; 138 139 inline CallConvMode operator|(CallConvMode a, CallConvMode b) 140 { 141 return CallConvMode(a.value_ | b.value_); 142 } 143 144 /** 145 * CallConv - just holds information about calling convention in current architecture. 146 */ 147 class CallingConvention { 148 public: 149 virtual ~CallingConvention() = default; 150 151 // All possible reasons for call and return 152 enum Reason { 153 // Reason for save/restore registers 154 FUNCTION, // Function inside programm 155 NATIVE, // native function 156 PROGRAMM // Enter/exit from programm (UNSUPPORTED) 157 }; 158 159 // Implemented in target.cpp 160 static CallingConvention *Create(ArenaAllocator *arena_allocator, Encoder *enc, RegistersDescription *descr, 161 Arch arch, bool is_panda_abi = false, bool is_osr = false, bool is_dyn = false, 162 bool print_asm = false); 163 164 public: CallingConvention(ArenaAllocator * allocator,Encoder * enc,RegistersDescription * descr,CallConvMode mode)165 CallingConvention(ArenaAllocator *allocator, Encoder *enc, RegistersDescription *descr, CallConvMode mode) 166 : allocator_(allocator), encoder_(enc), regfile_(descr), mode_(mode) 167 { 168 } 169 GetAllocator()170 ArenaAllocator *GetAllocator() const 171 { 172 return allocator_; 173 } 174 GetEncoder()175 Encoder *GetEncoder() const 176 { 177 return encoder_; 178 } 179 SetEncoder(Encoder * enc)180 void SetEncoder(Encoder *enc) 181 { 182 encoder_ = enc; 183 } 184 GetRegfile()185 RegistersDescription *GetRegfile() const 186 { 187 return regfile_; 188 } 189 IsValid()190 virtual bool IsValid() const 191 { 192 return false; 193 } 194 GetMode()195 CallConvMode GetMode() const 196 { 197 return mode_; 198 } 199 IsPandaMode()200 bool IsPandaMode() const 201 { 202 return mode_.IsPanda(); 203 } 204 IsOsrMode()205 bool IsOsrMode() const 206 { 207 return mode_.IsOsr(); 208 } 209 IsDynMode()210 bool IsDynMode() const 211 { 212 return mode_.IsDyn(); 213 } 214 215 #ifdef PANDA_COMPILER_CFI GetCfiInfo()216 CfiInfo &GetCfiInfo() 217 { 218 return cfi_info_; 219 } 220 GetCfiInfo()221 const CfiInfo &GetCfiInfo() const 222 { 223 return cfi_info_; 224 } ProvideCFI()225 static constexpr bool ProvideCFI() 226 { 227 return true; 228 } 229 #else ProvideCFI()230 static constexpr bool ProvideCFI() 231 { 232 return false; 233 } 234 #endif 235 236 // Prologue/Epilogue interfaces 237 virtual void GeneratePrologue(const FrameInfo &frame_info) = 0; 238 virtual void GenerateEpilogue(const FrameInfo &frame_info, std::function<void()> post_job) = 0; 239 240 virtual void GenerateNativePrologue(const FrameInfo &frame_info) = 0; 241 virtual void GenerateNativeEpilogue(const FrameInfo &frame_info, std::function<void()> post_job) = 0; 242 243 // Code generation completion interfaces 244 virtual void *GetCodeEntry() = 0; 245 virtual uint32_t GetCodeSize() = 0; 246 247 // Calculating information about parameters and save regs_offset registers for special needs 248 virtual ParameterInfo *GetParameterInfo(uint8_t regs_offset) = 0; 249 250 NO_COPY_SEMANTIC(CallingConvention); 251 NO_MOVE_SEMANTIC(CallingConvention); 252 253 private: 254 // Must not use ExecModel! 255 ArenaAllocator *allocator_ {nullptr}; 256 Encoder *encoder_ {nullptr}; 257 RegistersDescription *regfile_ {nullptr}; 258 #ifdef PANDA_COMPILER_CFI 259 CfiInfo cfi_info_; 260 #endif 261 CallConvMode mode_ {0}; 262 }; 263 } // namespace panda::compiler 264 265 #endif // COMPILER_OPTIMIZER_CODEGEN_CALLCONV_H_ 266