• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Low-level calling convention
17 */
18 #include "target/amd64/target.h"
19 
20 namespace panda::compiler::amd64 {
21 
Amd64CallingConvention(ArenaAllocator * allocator,Encoder * enc,RegistersDescription * descr,CallConvMode mode)22 Amd64CallingConvention::Amd64CallingConvention(ArenaAllocator *allocator, Encoder *enc, RegistersDescription *descr,
23                                                CallConvMode mode)
24     : CallingConvention(allocator, enc, descr, mode)
25 {
26 }
27 
GetParameterInfo(uint8_t regs_offset)28 ParameterInfo *Amd64CallingConvention::GetParameterInfo(uint8_t regs_offset)
29 {
30     auto param_info = GetAllocator()->New<amd64::Amd64ParameterInfo>();
31     // reserve first parameter to method pointer
32     for (int i = 0; i < regs_offset; ++i) {
33         param_info->GetNativeParam(INT64_TYPE);
34     }
35     return param_info;
36 }
37 
GetCodeEntry()38 void *Amd64CallingConvention::GetCodeEntry()
39 {
40     auto code = static_cast<Amd64Encoder *>(GetEncoder())->GetMasm()->code();
41     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
42     return reinterpret_cast<void *>(code->baseAddress());
43 }
44 
GetCodeSize()45 uint32_t Amd64CallingConvention::GetCodeSize()
46 {
47     return static_cast<Amd64Encoder *>(GetEncoder())->GetMasm()->code()->codeSize();
48 }
49 
PushRegs(RegList regs,RegList vregs)50 size_t Amd64CallingConvention::PushRegs(RegList regs, RegList vregs)
51 {
52     size_t regs_count {0};
53     size_t vregs_count {0};
54 
55     for (uint32_t i = 0; i < MAX_NUM_REGS; ++i) {
56         uint32_t ii {MAX_NUM_REGS - i - 1};
57         if (vregs.Has(ii)) {
58             ++vregs_count;
59             GetMasm()->sub(asmjit::x86::rsp, asmjit::imm(DOUBLE_WORD_SIZE_BYTE));
60             GetMasm()->movsd(asmjit::x86::ptr(asmjit::x86::rsp), asmjit::x86::xmm(ii));
61         }
62     }
63 
64     for (uint32_t i = 0; i < MAX_NUM_REGS; ++i) {
65         uint32_t ii {MAX_NUM_REGS - i - 1};
66         if (regs.Has(ii)) {
67             ++regs_count;
68             GetMasm()->push(asmjit::x86::gpq(ConvertRegNumber(ii)));
69         }
70     }
71 
72     return vregs_count + regs_count;
73 }
74 
PopRegs(RegList regs,RegList vregs)75 size_t Amd64CallingConvention::PopRegs(RegList regs, RegList vregs)
76 {
77     size_t regs_count {0};
78     size_t vregs_count {0};
79 
80     for (uint32_t i = 0; i < MAX_NUM_REGS; ++i) {
81         if (regs.Has(i)) {
82             ++regs_count;
83             GetMasm()->pop(asmjit::x86::gpq(ConvertRegNumber(i)));
84         }
85     }
86 
87     for (uint32_t i = 0; i < MAX_NUM_REGS; ++i) {
88         if (vregs.Has(i)) {
89             ++vregs_count;
90             GetMasm()->movsd(asmjit::x86::xmm(i), asmjit::x86::ptr(asmjit::x86::rsp));
91             GetMasm()->add(asmjit::x86::rsp, asmjit::imm(DOUBLE_WORD_SIZE_BYTE));
92         }
93     }
94 
95     return vregs_count + regs_count;
96 }
97 
GetNativeParam(const TypeInfo & type)98 std::variant<Reg, uint8_t> Amd64ParameterInfo::GetNativeParam(const TypeInfo &type)
99 {
100     if (type.IsFloat()) {
101         if (current_vector_number_ > MAX_VECTOR_PARAM_ID) {
102             return current_stack_offset_++;
103         }
104         return Reg(current_vector_number_++, type);
105     }
106     if (current_scalar_number_ > MAX_SCALAR_PARAM_ID) {
107         return current_stack_offset_++;
108     }
109 
110     return Target(Arch::X86_64).GetParamReg(current_scalar_number_++, type);
111 }
112 
GetNextLocation(DataType::Type type)113 Location Amd64ParameterInfo::GetNextLocation(DataType::Type type)
114 {
115     if (DataType::IsFloatType(type)) {
116         if (current_vector_number_ > MAX_VECTOR_PARAM_ID) {
117             return Location::MakeStackArgument(current_stack_offset_++);
118         }
119         return Location::MakeFpRegister(current_vector_number_++);
120     }
121     if (current_scalar_number_ > MAX_SCALAR_PARAM_ID) {
122         return Location::MakeStackArgument(current_stack_offset_++);
123     }
124     Target target(Arch::X86_64);
125     return Location::MakeRegister(target.GetParamRegId(current_scalar_number_++));
126 }
127 
GeneratePrologue(const FrameInfo & frame_info)128 void Amd64CallingConvention::GeneratePrologue([[maybe_unused]] const FrameInfo &frame_info)
129 {
130     auto encoder = GetEncoder();
131     const CFrameLayout &fl = encoder->GetFrameLayout();
132     auto fp_reg = GetTarget().GetFrameReg();
133     auto sp_reg = GetTarget().GetStackReg();
134 
135     // we do not push return address, because in amd64 call instruction already pushed it
136     GetMasm()->push(asmjit::x86::rbp);  // frame pointer
137     SET_CFI_OFFSET(push_fplr, encoder->GetCursorOffset());
138 
139     encoder->EncodeMov(fp_reg, sp_reg);
140     SET_CFI_OFFSET(set_fp, encoder->GetCursorOffset());
141     encoder->EncodeSub(sp_reg, sp_reg, Imm(2U * DOUBLE_WORD_SIZE_BYTE));
142 
143     encoder->EncodeStr(GetTarget().GetParamReg(0), MemRef(sp_reg, DOUBLE_WORD_SIZE_BYTE));
144 
145     // Reset OSR flag and set HasFloatRegsFlag
146     auto flags {static_cast<uint64_t>(frame_info.GetHasFloatRegs()) << CFrameLayout::HasFloatRegsFlag::START_BIT};
147     encoder->EncodeSti(Imm(flags), MemRef(sp_reg));
148     // Allocate space for locals
149     encoder->EncodeSub(sp_reg, sp_reg, Imm(DOUBLE_WORD_SIZE_BYTE * (CFrameSlots::Start() - CFrameData::Start())));
150     static_assert((CFrameLayout::GetLocalsCount() & 1U) == 0);
151 
152     RegList callee_regs {GetCalleeRegsMask(Arch::X86_64, false).GetValue()};
153     RegList callee_vregs {GetCalleeRegsMask(Arch::X86_64, true).GetValue()};
154     SET_CFI_CALLEE_REGS(RegMask(static_cast<size_t>(callee_regs)));
155     SET_CFI_CALLEE_VREGS(VRegMask(static_cast<size_t>(callee_vregs)));
156     PushRegs(callee_regs, callee_vregs);
157     SET_CFI_OFFSET(push_callees, encoder->GetCursorOffset());
158 
159     encoder->EncodeSub(
160         sp_reg, sp_reg,
161         Imm((fl.GetSpillsCount() + fl.GetCallerRegistersCount(false) + fl.GetCallerRegistersCount(true)) *
162             DOUBLE_WORD_SIZE_BYTE));
163 }
164 
GenerateEpilogue(const FrameInfo & frame_info,std::function<void ()> post_job)165 void Amd64CallingConvention::GenerateEpilogue([[maybe_unused]] const FrameInfo &frame_info,
166                                               std::function<void()> post_job)
167 {
168     auto encoder = GetEncoder();
169     const CFrameLayout &fl = encoder->GetFrameLayout();
170     auto sp_reg = GetTarget().GetStackReg();
171 
172     if (post_job) {
173         post_job();
174     }
175 
176     encoder->EncodeAdd(
177         sp_reg, sp_reg,
178         Imm((fl.GetSpillsCount() + fl.GetCallerRegistersCount(false) + fl.GetCallerRegistersCount(true)) *
179             DOUBLE_WORD_SIZE_BYTE));
180 
181     PopRegs(RegList(GetCalleeRegsMask(Arch::X86_64, false).GetValue()),
182             RegList(GetCalleeRegsMask(Arch::X86_64, true).GetValue()));
183     SET_CFI_OFFSET(pop_callees, encoder->GetCursorOffset());
184 
185     // X86_64 doesn't support OSR mode
186     ASSERT(!IsOsrMode());
187     // Support restoring of LR and FP registers once OSR is supported in x86_64
188     static_assert(!ArchTraits<Arch::X86_64>::SUPPORT_OSR);
189     constexpr auto SHIFT = DOUBLE_WORD_SIZE_BYTE * (2 + CFrameSlots::Start() - CFrameData::Start());
190     encoder->EncodeAdd(sp_reg, sp_reg, Imm(SHIFT));
191 
192     GetMasm()->pop(asmjit::x86::rbp);  // frame pointer
193     SET_CFI_OFFSET(pop_fplr, encoder->GetCursorOffset());
194     GetMasm()->ret();
195 }
196 }  // namespace panda::compiler::amd64
197