• 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 #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