/** * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef COMPILER_OPTIMIZER_CODEGEN_CALLCONV_H_ #define COMPILER_OPTIMIZER_CODEGEN_CALLCONV_H_ /* Codegen Hi-Level calling-convention interface Also contains branches targets(labels) Responsible for Branches and jump-encoding Labels (points for jump) Conditional instructions */ #include #include "encode.h" #include "compiler/optimizer/ir/datatype.h" #include "compiler/optimizer/ir/locations.h" #include "compiler/optimizer/code_generator/frame_info.h" namespace panda::compiler { class ParameterInfo { public: using SlotID = uint8_t; ParameterInfo() = default; virtual ~ParameterInfo() = default; // Get next native parameter, on condition, what previous list - in vector // Push data in Reg // Return register or stack_slot virtual std::variant GetNativeParam(const TypeInfo &) = 0; virtual Location GetNextLocation([[maybe_unused]] DataType::Type type) = 0; void Reset() { current_scalar_number_ = 0; current_vector_number_ = 0; current_stack_offset_ = 0; } NO_COPY_SEMANTIC(ParameterInfo); NO_MOVE_SEMANTIC(ParameterInfo); protected: uint32_t current_scalar_number_ {0}; // NOLINT(misc-non-private-member-variables-in-classes) uint32_t current_vector_number_ {0}; // NOLINT(misc-non-private-member-variables-in-classes) uint8_t current_stack_offset_ {0}; // NOLINT(misc-non-private-member-variables-in-classes) }; #ifdef PANDA_COMPILER_CFI struct CfiOffsets { size_t push_fplr {0}; size_t set_fp {0}; size_t push_callees {0}; size_t pop_callees {0}; size_t pop_fplr {0}; }; struct CfiInfo { CfiOffsets offsets; RegMask callee_regs; VRegMask callee_vregs; }; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define SET_CFI_OFFSET(field, value) GetCfiInfo().offsets.field = value // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define SET_CFI_CALLEE_REGS(value) GetCfiInfo().callee_regs = value // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define SET_CFI_CALLEE_VREGS(value) GetCfiInfo().callee_vregs = value #else // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define SET_CFI_OFFSET(field, value) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define SET_CFI_CALLEE_REGS(value) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define SET_CFI_CALLEE_VREGS(value) #endif /** * Specifies CallingConvention mode. */ class CallConvMode final { public: explicit CallConvMode(uint32_t value) : value_(value) {} DEFAULT_COPY_SEMANTIC(CallConvMode); DEFAULT_MOVE_SEMANTIC(CallConvMode); ~CallConvMode() = default; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define DECLARE_CALLCONV_MODE(name) \ static CallConvMode name(bool set = true) \ { \ return CallConvMode(Flag##name ::Encode(set)); \ } \ void Set##name(bool v) \ { \ Flag##name ::Set(v, &value_); \ } \ bool Is##name() const \ { \ return Flag##name ::Get(value_); \ } // Panda ABI convention (native - otherwise) DECLARE_CALLCONV_MODE(Panda); // Compile for osr (jit - otherwise) DECLARE_CALLCONV_MODE(Osr); // The method from dynamic language DECLARE_CALLCONV_MODE(Dyn); #undef DECLARE_CALLCONV_MODE private: using FlagPanda = BitField; using FlagOsr = FlagPanda::NextFlag; using FlagDyn = FlagOsr::NextFlag; uint32_t value_ {0}; friend CallConvMode operator|(CallConvMode a, CallConvMode b); }; inline CallConvMode operator|(CallConvMode a, CallConvMode b) { return CallConvMode(a.value_ | b.value_); } /** * CallConv - just holds information about calling convention in current architecture. */ class CallingConvention { public: virtual ~CallingConvention() = default; // All possible reasons for call and return enum Reason { // Reason for save/restore registers FUNCTION, // Function inside programm NATIVE, // native function PROGRAMM // Enter/exit from programm (UNSUPPORTED) }; // Implemented in target.cpp static CallingConvention *Create(ArenaAllocator *arena_allocator, Encoder *enc, RegistersDescription *descr, Arch arch, bool is_panda_abi = false, bool is_osr = false, bool is_dyn = false, bool print_asm = false); public: CallingConvention(ArenaAllocator *allocator, Encoder *enc, RegistersDescription *descr, CallConvMode mode) : allocator_(allocator), encoder_(enc), regfile_(descr), mode_(mode) { } ArenaAllocator *GetAllocator() const { return allocator_; } Encoder *GetEncoder() const { return encoder_; } void SetEncoder(Encoder *enc) { encoder_ = enc; } RegistersDescription *GetRegfile() const { return regfile_; } virtual bool IsValid() const { return false; } CallConvMode GetMode() const { return mode_; } bool IsPandaMode() const { return mode_.IsPanda(); } bool IsOsrMode() const { return mode_.IsOsr(); } bool IsDynMode() const { return mode_.IsDyn(); } #ifdef PANDA_COMPILER_CFI CfiInfo &GetCfiInfo() { return cfi_info_; } const CfiInfo &GetCfiInfo() const { return cfi_info_; } static constexpr bool ProvideCFI() { return true; } #else static constexpr bool ProvideCFI() { return false; } #endif // Prologue/Epilogue interfaces virtual void GeneratePrologue(const FrameInfo &frame_info) = 0; virtual void GenerateEpilogue(const FrameInfo &frame_info, std::function post_job) = 0; virtual void GenerateNativePrologue(const FrameInfo &frame_info) = 0; virtual void GenerateNativeEpilogue(const FrameInfo &frame_info, std::function post_job) = 0; // Code generation completion interfaces virtual void *GetCodeEntry() = 0; virtual uint32_t GetCodeSize() = 0; // Calculating information about parameters and save regs_offset registers for special needs virtual ParameterInfo *GetParameterInfo(uint8_t regs_offset) = 0; NO_COPY_SEMANTIC(CallingConvention); NO_MOVE_SEMANTIC(CallingConvention); private: // Must not use ExecModel! ArenaAllocator *allocator_ {nullptr}; Encoder *encoder_ {nullptr}; RegistersDescription *regfile_ {nullptr}; #ifdef PANDA_COMPILER_CFI CfiInfo cfi_info_; #endif CallConvMode mode_ {0}; }; } // namespace panda::compiler #endif // COMPILER_OPTIMIZER_CODEGEN_CALLCONV_H_