1 /*
2 * Copyright (c) 2023 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 "cg_stackmap_computation.h"
17 #include "live.h"
18
19 namespace maplebe {
20 #define STACKMAP_DUMP (CG_DEBUG_FUNC(f))
21
SetStackmapDerivedInfo()22 void StackmapComputation::SetStackmapDerivedInfo()
23 {
24 FOR_ALL_BB(bb, &cgFunc)
25 {
26 FOR_BB_INSNS(insn, bb)
27 {
28 if (!insn->IsMachineInstruction()) {
29 continue;
30 }
31 const InsnDesc *md = insn->GetDesc();
32 uint32 opndNum = insn->GetOperandSize();
33 for (uint32 i = 0; i < opndNum; ++i) {
34 const OpndDesc *regProp = md->GetOpndDes(i);
35 DEBUG_ASSERT(regProp != nullptr, "pointer is null in StackmapComputation::SetStackMapDerivedInfo");
36 bool isDef = regProp->IsRegDef();
37 Operand &opnd = insn->GetOperand(i);
38 if (isDef) {
39 auto ®Opnd = static_cast<RegOperand &>(opnd);
40 uint32 regNO = regOpnd.GetRegisterNumber();
41 if (regOpnd.GetBaseRefOpnd() != nullptr) {
42 // set the base reference of derived reference for stackmap
43 derivedRef2Base[regNO] = regOpnd.GetBaseRefOpnd();
44 }
45 }
46 }
47 }
48 }
49 }
50
GetSpillMem(uint32 vRegNO,bool isDest,Insn & insn,regno_t regNO,bool & isOutOfRange,uint32 bitSize)51 MemOperand *StackmapComputation::GetSpillMem(uint32 vRegNO, bool isDest, Insn &insn, regno_t regNO,
52 bool &isOutOfRange, uint32 bitSize)
53 {
54 MemOperand *memOpnd = regInfo->GetOrCreatSpillMem(vRegNO, bitSize);
55 return regInfo->AdjustMemOperandIfOffsetOutOfRange(memOpnd, std::make_pair(vRegNO, regNO), isDest, insn,
56 isOutOfRange);
57 }
58
SpillOperand(Insn & insn,regno_t regNO)59 void StackmapComputation::SpillOperand(Insn &insn, regno_t regNO)
60 {
61 bool isOutOfRange = false;
62 uint32 regSize = GetPrimTypeSize(PTY_ref) * k8BitSize;
63 PrimType spType = PTY_ref;
64 #if TARGX86_64
65 RegOperand &srcOpnd = cgFunc.GetOpndBuilder()->CreateVReg(regNO, regSize, cgFunc.GetRegTyFromPrimTy(spType));
66 #else
67 RegOperand &srcOpnd = cgFunc.GetOrCreateVirtualRegisterOperand(regNO);
68 #endif
69
70 MemOperand *memOpnd = GetSpillMem(regNO, true, insn, kInvalidRegNO, isOutOfRange, regSize);
71 Insn *stInsn = regInfo->BuildStrInsn(regSize, spType, srcOpnd, *memOpnd);
72 insn.GetBB()->InsertInsnBefore(insn, *stInsn);
73 }
74
LoadOperand(Insn & insn,regno_t regNO)75 void StackmapComputation::LoadOperand(Insn &insn, regno_t regNO)
76 {
77 bool isOutOfRange = false;
78 uint32 regSize = GetPrimTypeSize(PTY_ref) * k8BitSize;
79 PrimType spType = PTY_ref;
80
81 #if TARGX86_64
82 RegOperand &resOpnd = cgFunc.GetOpndBuilder()->CreateVReg(regNO, regSize, cgFunc.GetRegTyFromPrimTy(spType));
83 #else
84 RegOperand &resOpnd = cgFunc.GetOrCreateVirtualRegisterOperand(regNO);
85 #endif
86
87 Insn *nextInsn = insn.GetNext();
88 MemOperand *memOpnd = GetSpillMem(regNO, false, insn, kInvalidRegNO, isOutOfRange, regSize);
89 Insn *ldInsn = regInfo->BuildLdrInsn(regSize, spType, resOpnd, *memOpnd);
90 if (isOutOfRange && nextInsn != nullptr) {
91 insn.GetBB()->InsertInsnBefore(*nextInsn, *ldInsn);
92 } else if (isOutOfRange && nextInsn == nullptr) {
93 insn.GetBB()->AppendInsn(*ldInsn);
94 } else {
95 insn.GetBB()->InsertInsnAfter(insn, *ldInsn);
96 }
97 }
98
RelocateStackmapInfo()99 void StackmapComputation::RelocateStackmapInfo()
100 {
101 const auto &referenceMapInsns = cgFunc.GetStackMapInsns();
102 for (auto *insn : referenceMapInsns) {
103 auto &deoptInfo = insn->GetStackMap()->GetDeoptInfo();
104 const auto &deoptBundleInfo = deoptInfo.GetDeoptBundleInfo();
105 for (const auto &item : deoptBundleInfo) {
106 const auto *opnd = item.second;
107 if (!opnd->IsRegister()) {
108 continue;
109 }
110 regno_t regNO = (static_cast<const RegOperand *>(opnd))->GetRegisterNumber();
111 SpillOperand(*insn, regNO);
112 LoadOperand(*insn, regNO);
113 }
114
115 for (auto regNO : insn->GetStackMapLiveIn()) {
116 if (!cgFunc.IsRegReference(regNO)) {
117 continue;
118 }
119 auto itr = derivedRef2Base.find(regNO);
120 if (itr != derivedRef2Base.end()) {
121 SpillOperand(*insn, itr->second->GetRegisterNumber());
122 LoadOperand(*insn, itr->second->GetRegisterNumber());
123 }
124 SpillOperand(*insn, regNO);
125 LoadOperand(*insn, regNO);
126 }
127 }
128 }
129
CollectReferenceMap()130 void StackmapComputation::CollectReferenceMap()
131 {
132 const auto &referenceMapInsns = cgFunc.GetStackMapInsns();
133 if (needDump) {
134 LogInfo::MapleLogger() << "===========reference map stack info================\n";
135 }
136
137 int insnNum = 0;
138
139 for (auto *insn : referenceMapInsns) {
140 insnNum++;
141 for (auto regNO : insn->GetStackMapLiveIn()) {
142 if (!cgFunc.IsRegReference(regNO)) {
143 continue;
144 }
145
146 auto itr = derivedRef2Base.find(regNO);
147 if (itr != derivedRef2Base.end()) {
148 auto baseRegNum = (itr->second)->GetRegisterNumber();
149 MemOperand *baseRegMemOpnd = cgFunc.GetOrCreatSpillMem(baseRegNum, k64BitSize);
150 int64 baseRefMemoffset = baseRegMemOpnd->GetOffsetImmediate()->GetOffsetValue();
151 insn->GetStackMap()->GetReferenceMap().ReocordStackRoots(baseRefMemoffset);
152 if (needDump) {
153 LogInfo::MapleLogger() << "--------insn num: " << insnNum
154 << " base regNO: " << baseRegNum << " offset: "
155 << baseRefMemoffset << std::endl;
156 }
157 }
158 MemOperand *memOperand = cgFunc.GetOrCreatSpillMem(regNO, k64BitSize);
159 int64 offset = memOperand->GetOffsetImmediate()->GetOffsetValue();
160 insn->GetStackMap()->GetReferenceMap().ReocordStackRoots(offset);
161 if (itr == derivedRef2Base.end()) {
162 insn->GetStackMap()->GetReferenceMap().ReocordStackRoots(offset);
163 }
164 if (needDump) {
165 LogInfo::MapleLogger() << "--------insn num: " << insnNum << " regNO: " << regNO
166 << " offset: " << offset << std::endl;
167 }
168 }
169 }
170
171 if (needDump) {
172 LogInfo::MapleLogger() << "===========reference map stack info end================\n";
173 }
174 if (needDump) {
175 LogInfo::MapleLogger() << "===========reference map info================\n";
176 for (auto *insn : referenceMapInsns) {
177 LogInfo::MapleLogger() << " referenceMap insn: ";
178 insn->Dump();
179 insn->GetStackMap()->GetReferenceMap().Dump();
180 }
181 }
182 }
183
SolveRegOpndDeoptInfo(const RegOperand & regOpnd,DeoptInfo & deoptInfo,int32 deoptVregNO) const184 void StackmapComputation::SolveRegOpndDeoptInfo(const RegOperand ®Opnd, DeoptInfo &deoptInfo,
185 int32 deoptVregNO) const
186 {
187 if (!regOpnd.IsVirtualRegister()) {
188 // Get Register No
189 deoptInfo.RecordDeoptVreg2LocationInfo(deoptVregNO, LocationInfo({kInRegister, 0}));
190 return;
191 }
192 // process virtual RegOperand
193 regno_t vRegNO = regOpnd.GetRegisterNumber();
194 MemOperand *memOpnd = cgFunc.GetOrCreatSpillMem(vRegNO, regOpnd.GetSize());
195 SolveMemOpndDeoptInfo(*(static_cast<const MemOperand *>(memOpnd)), deoptInfo, deoptVregNO);
196 }
197
SolveMemOpndDeoptInfo(const MemOperand & memOpnd,DeoptInfo & deoptInfo,int32 deoptVregNO) const198 void StackmapComputation::SolveMemOpndDeoptInfo(const MemOperand &memOpnd, DeoptInfo &deoptInfo,
199 int32 deoptVregNO) const
200 {
201 int64 offset = memOpnd.GetOffsetImmediate()->GetOffsetValue();
202 deoptInfo.RecordDeoptVreg2LocationInfo(deoptVregNO, LocationInfo({kOnStack, offset}));
203 }
204
CollectDeoptInfo()205 void StackmapComputation::CollectDeoptInfo()
206 {
207 const auto referenceMapInsns = cgFunc.GetStackMapInsns();
208 for (auto *insn : referenceMapInsns) {
209 auto &deoptInfo = insn->GetStackMap()->GetDeoptInfo();
210 const auto &deoptBundleInfo = deoptInfo.GetDeoptBundleInfo();
211 if (deoptBundleInfo.empty()) {
212 continue;
213 }
214 for (const auto &item : deoptBundleInfo) {
215 const auto *opnd = item.second;
216 if (opnd->IsRegister()) {
217 SolveRegOpndDeoptInfo(*static_cast<const RegOperand *>(opnd), deoptInfo, item.first);
218 continue;
219 }
220 if (opnd->IsImmediate()) {
221 const auto *immOpnd = static_cast<const ImmOperand *>(opnd);
222 deoptInfo.RecordDeoptVreg2LocationInfo(item.first, LocationInfo({kInConstValue, immOpnd->GetValue()}));
223 continue;
224 }
225 if (opnd->IsMemoryAccessOperand()) {
226 SolveMemOpndDeoptInfo(*(static_cast<const MemOperand *>(opnd)), deoptInfo, item.first);
227 continue;
228 }
229 DEBUG_ASSERT(false, "can't reach here!");
230 }
231 }
232 if (needDump) {
233 LogInfo::MapleLogger() << "===========deopt info================\n";
234 for (auto *insn : referenceMapInsns) {
235 LogInfo::MapleLogger() << "---- deoptInfo insn: ";
236 insn->Dump();
237 insn->GetStackMap()->GetDeoptInfo().Dump();
238 }
239 }
240 }
241
run()242 void StackmapComputation::run()
243 {
244 if (needDump) {
245 LogInfo::MapleLogger() << "===========StackmapComputation PhaseRun================\n";
246 }
247 SetStackmapDerivedInfo();
248 RelocateStackmapInfo();
249 CollectReferenceMap();
250 CollectDeoptInfo();
251 }
252
PhaseRun(maplebe::CGFunc & f)253 bool CgStackmapComputation::PhaseRun(maplebe::CGFunc &f)
254 {
255 MemPool *phaseMp = GetPhaseMemPool();
256 LiveAnalysis *live = nullptr;
257 live = GET_ANALYSIS(CgLiveAnalysis, f);
258 StackmapComputation *stackmapComputation = nullptr;
259 stackmapComputation = GetPhaseAllocator()->New<StackmapComputation>(f, *phaseMp);
260 stackmapComputation->SetNeedDump(STACKMAP_DUMP);
261 stackmapComputation->run();
262
263 if (live != nullptr) {
264 live->ClearInOutDataInfo();
265 }
266
267 f.SetStackMapComputed();
268
269 return true;
270 }
271
GetAnalysisDependence(maple::AnalysisDep & aDep) const272 void CgStackmapComputation::GetAnalysisDependence(maple::AnalysisDep &aDep) const
273 {
274 aDep.AddRequired<CgLiveAnalysis>();
275 }
276
277 MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgStackmapComputation, stackmapcomputation)
278 } // namespace maplebe
279