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