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 #include "codegen_boundary.h"
17 #include "utils/cframe_layout.h"
18
19 namespace panda::compiler {
20
GeneratePrologue()21 void CodegenBoundary::GeneratePrologue()
22 {
23 SCOPED_DISASM_STR(this, "Boundary Prologue");
24 auto encoder = GetEncoder();
25 auto frame = GetFrameInfo();
26
27 if (GetTarget().SupportLinkReg()) {
28 ScopedTmpReg tmp(encoder);
29 static constexpr ssize_t FP_OFFSET = 3;
30 static constexpr ssize_t LR_OFFSET = 2;
31 encoder->EncodeMov(tmp, Imm(FrameBridgeKind::COMPILED_CODE_TO_INTERPRETER));
32 encoder->EncodeStp(tmp, GetTarget().GetLinkReg(),
33 MemRef(GetTarget().GetStackReg(), -LR_OFFSET * GetTarget().WordSize()));
34 encoder->EncodeStr(GetTarget().GetFrameReg(),
35 MemRef(GetTarget().GetStackReg(), -FP_OFFSET * GetTarget().WordSize()));
36
37 encoder->EncodeSub(GetTarget().GetLinkReg(), GetTarget().GetStackReg(),
38 Imm(FP_OFFSET * GetTarget().WordSize()));
39 encoder->EncodeStr(GetTarget().GetLinkReg(), MemRef(ThreadReg(), GetRuntime()->GetTlsFrameOffset(GetArch())));
40 } else {
41 static constexpr ssize_t FP_OFFSET = 2;
42 encoder->EncodeSti(Imm(FrameBridgeKind::COMPILED_CODE_TO_INTERPRETER),
43 MemRef(GetTarget().GetStackReg(), -1 * GetTarget().WordSize()));
44 encoder->EncodeStr(GetTarget().GetFrameReg(),
45 MemRef(GetTarget().GetStackReg(), -FP_OFFSET * GetTarget().WordSize()));
46
47 {
48 ScopedTmpReg tmp(GetEncoder());
49 encoder->EncodeSub(tmp, GetTarget().GetStackReg(), Imm(2U * GetTarget().WordSize()));
50 encoder->EncodeStr(tmp, MemRef(ThreadReg(), GetRuntime()->GetTlsFrameOffset(GetArch())));
51 }
52 }
53
54 encoder->EncodeSub(GetTarget().GetStackReg(), GetTarget().GetStackReg(), Imm(frame->GetFrameSize()));
55
56 auto callee_regs =
57 GetCalleeRegsMask(GetArch(), false) & ~GetTarget().GetTempRegsMask().to_ulong() & ~ThreadReg().GetId();
58 auto callee_vregs = GetCalleeRegsMask(GetArch(), true) & ~GetTarget().GetTempVRegsMask().to_ulong();
59 auto caller_regs = GetCallerRegsMask(GetArch(), false) & ~GetTarget().GetTempRegsMask().to_ulong();
60 auto caller_vregs = GetCallerRegsMask(GetArch(), true) & ~GetTarget().GetTempRegsMask().to_ulong();
61
62 Reg base = GetTarget().GetFrameReg();
63 auto fl = GetFrameLayout();
64 {
65 SCOPED_DISASM_STR(this, "Save caller registers");
66 ssize_t offset = fl.GetOffset<CFrameLayout::FP, CFrameLayout::SLOTS>(CFrameLayout::GetStackStartSlot() +
67 fl.GetCallerLastSlot(false));
68 encoder->SaveRegisters(caller_regs, false, -offset, base, GetCallerRegsMask(GetArch(), false));
69 offset = fl.GetOffset<CFrameLayout::FP, CFrameLayout::SLOTS>(CFrameLayout::GetStackStartSlot() +
70 fl.GetCallerLastSlot(true));
71 encoder->SaveRegisters(caller_vregs, true, -offset, base, GetCallerRegsMask(GetArch(), true));
72 }
73 {
74 SCOPED_DISASM_STR(this, "Save callee registers");
75 base = frame->GetCalleesRelativeFp() ? GetTarget().GetFrameReg() : GetTarget().GetStackReg();
76 encoder->SaveRegisters(callee_regs, false, frame->GetCalleesOffset(), base,
77 GetCalleeRegsMask(GetArch(), false));
78 encoder->SaveRegisters(callee_vregs, true, frame->GetFpCalleesOffset(), base,
79 GetCalleeRegsMask(GetArch(), true));
80 }
81 }
82
GenerateEpilogue()83 void CodegenBoundary::GenerateEpilogue()
84 {
85 SCOPED_DISASM_STR(this, "Boundary Epilogue");
86 RemoveBoundaryFrame(GetGraph()->GetEndBlock());
87 GetEncoder()->EncodeReturn();
88 }
89
CreateFrameInfo()90 void CodegenBoundary::CreateFrameInfo()
91 {
92 auto frame = GetGraph()->GetLocalAllocator()->New<FrameInfo>(
93 FrameInfo::PositionedCallers::Encode(false) | FrameInfo::PositionedCallees::Encode(true) |
94 FrameInfo::CallersRelativeFp::Encode(false) | FrameInfo::CalleesRelativeFp::Encode(false));
95 auto target = Target(GetGraph()->GetArch());
96 size_t spills_count = GetGraph()->GetStackSlotsCount();
97 size_t padding = 0;
98 size_t frame_size =
99 (CFrameLayout::HEADER_SIZE - (target.SupportLinkReg() ? 0 : 1) + GetCalleeRegsCount(target.GetArch(), false) +
100 GetCalleeRegsCount(target.GetArch(), true) + GetCallerRegsCount(target.GetArch(), false) +
101 GetCallerRegsCount(target.GetArch(), true) + spills_count) *
102 target.WordSize();
103 if (target.SupportLinkReg()) {
104 padding = RoundUp(frame_size, target.GetSpAlignment()) - frame_size;
105 } else {
106 if ((frame_size % target.GetSpAlignment()) == 0) {
107 padding = target.GetSpAlignment() - target.WordSize();
108 }
109 }
110 CHECK_EQ(padding % target.WordSize(), 0U);
111 spills_count += padding / target.WordSize();
112 frame_size += padding;
113 if (target.SupportLinkReg()) {
114 CHECK_EQ(frame_size % target.GetSpAlignment(), 0U);
115 } else {
116 CHECK_EQ(frame_size % target.GetSpAlignment(), target.GetSpAlignment() - target.WordSize());
117 }
118
119 ssize_t offset = spills_count;
120 frame->SetFpCallersOffset(offset);
121 offset += helpers::ToSigned(GetCallerRegsCount(target.GetArch(), true));
122 frame->SetCallersOffset(offset);
123 offset += helpers::ToSigned(GetCallerRegsCount(target.GetArch(), false));
124
125 frame->SetFpCalleesOffset(offset);
126 offset += helpers::ToSigned(GetCalleeRegsCount(target.GetArch(), true));
127 frame->SetCalleesOffset(offset);
128
129 frame->SetSpillsCount(spills_count);
130 frame->SetFrameSize(frame_size);
131
132 SetFrameInfo(frame);
133 }
134
IntrinsicTailCall(IntrinsicInst * inst)135 void CodegenBoundary::IntrinsicTailCall(IntrinsicInst *inst)
136 {
137 auto location = inst->GetLocation(0);
138 ASSERT(location.IsFixedRegister() && location.IsRegisterValid());
139 auto src = Reg(location.GetValue(), GetTarget().GetPtrRegType());
140 RegMask liveout_mask = GetLiveOut(inst->GetBasicBlock());
141 ScopedTmpRegLazy target(GetEncoder());
142 if (!liveout_mask.Test(src.GetId())) {
143 target.Acquire();
144 ASSERT(target.GetReg().IsValid());
145 GetEncoder()->EncodeMov(target, src);
146 src = target.GetReg();
147 }
148 ASSERT(src.IsValid());
149 RemoveBoundaryFrame(inst->GetBasicBlock());
150 GetEncoder()->EncodeJump(src);
151 }
152
RemoveBoundaryFrame(const BasicBlock * bb) const153 void CodegenBoundary::RemoveBoundaryFrame(const BasicBlock *bb) const
154 {
155 auto encoder = GetEncoder();
156 auto frame = GetFrameInfo();
157
158 RegMask liveout_mask = GetLiveOut(bb);
159
160 RegMask callee_regs = GetCalleeRegsMask(GetArch(), false) & ~GetTarget().GetTempRegsMask().to_ulong();
161 callee_regs &= ~liveout_mask;
162 callee_regs.reset(ThreadReg().GetId());
163 RegMask callee_vregs = GetCalleeRegsMask(GetArch(), true) & ~GetTarget().GetTempVRegsMask().to_ulong();
164 RegMask caller_regs = GetCallerRegsMask(GetArch(), false) & ~GetTarget().GetTempRegsMask().to_ulong();
165 caller_regs &= ~liveout_mask;
166 RegMask caller_vregs = GetCallerRegsMask(GetArch(), true) & ~GetTarget().GetTempRegsMask().to_ulong();
167
168 Reg base = GetTarget().GetFrameReg();
169 auto fl = GetFrameLayout();
170 ssize_t offset = fl.GetOffset<CFrameLayout::FP, CFrameLayout::SLOTS>(CFrameLayout::GetStackStartSlot() +
171 fl.GetCallerLastSlot(false));
172 encoder->LoadRegisters(caller_regs, false, -offset, base, GetCallerRegsMask(GetArch(), false));
173 offset = fl.GetOffset<CFrameLayout::FP, CFrameLayout::SLOTS>(CFrameLayout::GetStackStartSlot() +
174 fl.GetCallerLastSlot(true));
175 encoder->LoadRegisters(caller_vregs, true, -offset, base, GetCallerRegsMask(GetArch(), true));
176
177 base = frame->GetCalleesRelativeFp() ? GetTarget().GetFrameReg() : GetTarget().GetStackReg();
178 encoder->LoadRegisters(callee_regs, false, frame->GetCalleesOffset(), base, GetCalleeRegsMask(GetArch(), false));
179 encoder->LoadRegisters(callee_vregs, true, frame->GetFpCalleesOffset(), base, GetCalleeRegsMask(GetArch(), true));
180
181 encoder->EncodeAdd(GetTarget().GetStackReg(), GetTarget().GetStackReg(), Imm(frame->GetFrameSize()));
182
183 if (GetTarget().SupportLinkReg()) {
184 static constexpr ssize_t FP_OFFSET = -3;
185 encoder->EncodeLdr(GetTarget().GetLinkReg(), false,
186 MemRef(GetTarget().GetStackReg(), -1 * GetTarget().WordSize()));
187 encoder->EncodeLdr(GetTarget().GetFrameReg(), false,
188 MemRef(GetTarget().GetStackReg(), FP_OFFSET * GetTarget().WordSize()));
189 }
190 }
191 } // namespace panda::compiler
192