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 "clone.h"
17 #include <iostream>
18 #include <algorithm>
19 #include "mir_symbol.h"
20
21 // For some funcs, when we can ignore their return-values, we clone a new func of
22 // them without return-values. We configure a list to save these funcs and clone
23 // at the very beginning so that clones can also enjoy the optimizations after.
24 // This mainly contains the clone of funcbody(include labels, symbols, arguments,
25 // etc.) and the update of the new func infomation.
26 namespace maple {
ReplaceRetIgnored(MemPool * memPool)27 ReplaceRetIgnored::ReplaceRetIgnored(MemPool *memPool)
28 : memPool(memPool), allocator(memPool), toBeClonedFuncNames(allocator.Adapter())
29 {
30 }
31
RealShouldReplaceWithVoidFunc(Opcode op,size_t nRetSize,const MIRFunction & calleeFunc) const32 bool ReplaceRetIgnored::RealShouldReplaceWithVoidFunc(Opcode op, size_t nRetSize, const MIRFunction &calleeFunc) const
33 {
34 MIRType *returnType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(calleeFunc.GetReturnTyIdx());
35 return nRetSize == 0 &&
36 (op == OP_virtualcallassigned || op == OP_callassigned || op == OP_superclasscallassigned) &&
37 !calleeFunc.IsNative() && (returnType->GetKind() == kTypePointer) && (returnType->GetPrimType() == PTY_ref);
38 }
39
ShouldReplaceWithVoidFunc(const CallMeStmt & stmt,const MIRFunction & calleeFunc) const40 bool ReplaceRetIgnored::ShouldReplaceWithVoidFunc(const CallMeStmt &stmt, const MIRFunction &calleeFunc) const
41 {
42 return RealShouldReplaceWithVoidFunc(stmt.GetOp(), stmt.MustDefListSize(), calleeFunc);
43 }
44
GenerateNewBaseName(const MIRFunction & originalFunc) const45 std::string ReplaceRetIgnored::GenerateNewBaseName(const MIRFunction &originalFunc) const
46 {
47 return std::string(originalFunc.GetBaseFuncName()).append(kVoidRetSuffix);
48 }
49
GenerateNewFullName(const MIRFunction & originalFunc) const50 std::string ReplaceRetIgnored::GenerateNewFullName(const MIRFunction &originalFunc) const
51 {
52 const std::string &oldSignature = originalFunc.GetSignature();
53 auto retPos = oldSignature.find("_29");
54 constexpr auto retPosIndex = 3;
55 return std::string(originalFunc.GetBaseClassName())
56 .append(namemangler::kNameSplitterStr)
57 .append(GenerateNewBaseName(originalFunc))
58 .append(namemangler::kNameSplitterStr)
59 .append(oldSignature.substr(0, retPos + retPosIndex))
60 .append("V");
61 }
62
CloneLocalSymbol(const MIRSymbol & oldSym,const MIRFunction & newFunc)63 MIRSymbol *Clone::CloneLocalSymbol(const MIRSymbol &oldSym, const MIRFunction &newFunc)
64 {
65 MemPool *newMP = newFunc.GetDataMemPool();
66 MIRSymbol *newSym = newMP->New<MIRSymbol>(oldSym);
67 if (oldSym.GetSKind() == kStConst) {
68 newSym->SetKonst(oldSym.GetKonst()->Clone(*newMP));
69 } else if (oldSym.GetSKind() == kStPreg) {
70 newSym->SetPreg(newMP->New<MIRPreg>(*oldSym.GetPreg()));
71 } else if (oldSym.GetSKind() == kStFunc) {
72 CHECK_FATAL(false, "%s has unexpected local func symbol", oldSym.GetName().c_str());
73 }
74 return newSym;
75 }
76
CloneSymbols(MIRFunction & newFunc,const MIRFunction & oldFunc)77 void Clone::CloneSymbols(MIRFunction &newFunc, const MIRFunction &oldFunc)
78 {
79 size_t symTabSize = oldFunc.GetSymbolTabSize();
80 for (size_t i = oldFunc.GetFormalCount() + 1; i < symTabSize; ++i) {
81 MIRSymbol *sym = oldFunc.GetSymbolTabItem(static_cast<uint32>(i));
82 if (sym == nullptr) {
83 continue;
84 }
85 MIRSymbol *newSym = CloneLocalSymbol(*sym, newFunc);
86 if (!newFunc.GetSymTab()->AddStOutside(newSym)) {
87 CHECK_FATAL(false, "%s already existed in func %s", sym->GetName().c_str(), newFunc.GetName().c_str());
88 }
89 }
90 }
91
CloneLabels(MIRFunction & newFunc,const MIRFunction & oldFunc)92 void Clone::CloneLabels(MIRFunction &newFunc, const MIRFunction &oldFunc)
93 {
94 size_t labelTabSize = oldFunc.GetLabelTab()->GetLabelTableSize();
95 for (size_t i = 1; i < labelTabSize; ++i) {
96 const std::string &labelName = oldFunc.GetLabelTabItem(static_cast<uint32>(i));
97 GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(labelName);
98 (void)newFunc.GetLabelTab()->AddLabel(strIdx);
99 }
100 }
101
102 // Clone a function
CloneFunction(MIRFunction & originalFunction,const std::string & newBaseFuncName,MIRType * returnType) const103 MIRFunction *Clone::CloneFunction(MIRFunction &originalFunction, const std::string &newBaseFuncName,
104 MIRType *returnType) const
105 {
106 MapleAllocator cgAlloc(originalFunction.GetCodeMempool());
107 ArgVector argument(cgAlloc.Adapter());
108 CloneArgument(originalFunction, argument);
109 MIRType *retType = returnType;
110 if (retType == nullptr) {
111 retType = originalFunction.GetReturnType();
112 }
113 std::string fullName = originalFunction.GetBaseClassName();
114 const std::string &signature = originalFunction.GetSignature();
115 fullName = fullName.append(namemangler::kNameSplitterStr)
116 .append(newBaseFuncName)
117 .append(namemangler::kNameSplitterStr)
118 .append(signature);
119 MIRFunction *newFunc =
120 mirBuilder.CreateFunction(fullName, *retType, argument, false, originalFunction.GetBody() != nullptr);
121 CHECK_FATAL(newFunc != nullptr, "create cloned function failed");
122 mirBuilder.GetMirModule().AddFunction(newFunc);
123 Klass *klass = kh->GetKlassFromName(originalFunction.GetBaseClassName());
124 CHECK_FATAL(klass != nullptr, "getklass failed");
125 klass->AddMethod(newFunc);
126 newFunc->SetClassTyIdx(originalFunction.GetClassTyIdx());
127 MIRClassType *classType = klass->GetMIRClassType();
128 classType->GetMethods().push_back(MethodPair(
129 newFunc->GetStIdx(), TyidxFuncAttrPair(newFunc->GetFuncSymbol()->GetTyIdx(), originalFunction.GetFuncAttrs())));
130 newFunc->SetFlag(originalFunction.GetFlag());
131 newFunc->SetSrcPosition(originalFunction.GetSrcPosition());
132 newFunc->SetFuncAttrs(originalFunction.GetFuncAttrs());
133 newFunc->SetBaseClassFuncNames(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(fullName));
134 if (originalFunction.GetBody() != nullptr) {
135 CopyFuncInfo(originalFunction, *newFunc);
136 MIRFunction *originalCurrFunction = mirBuilder.GetCurrentFunctionNotNull();
137 mirBuilder.SetCurrentFunction(*newFunc);
138 newFunc->SetBody(
139 originalFunction.GetBody()->CloneTree(originalFunction.GetModule()->GetCurFuncCodeMPAllocator()));
140 CloneSymbols(*newFunc, originalFunction);
141 CloneLabels(*newFunc, originalFunction);
142 mirBuilder.SetCurrentFunction(*originalCurrFunction);
143 }
144 return newFunc;
145 }
146
CloneArgument(MIRFunction & originalFunction,ArgVector & argument) const147 void Clone::CloneArgument(MIRFunction &originalFunction, ArgVector &argument) const
148 {
149 for (size_t i = 0; i < originalFunction.GetFormalCount(); ++i) {
150 auto &formalName = originalFunction.GetFormalName(i);
151 argument.push_back(ArgPair(formalName, originalFunction.GetNthParamType(i)));
152 }
153 }
154
CopyFuncInfo(MIRFunction & originalFunction,MIRFunction & newFunc) const155 void Clone::CopyFuncInfo(MIRFunction &originalFunction, MIRFunction &newFunc) const
156 {
157 auto funcNameIdx = newFunc.GetBaseFuncNameStrIdx();
158 auto fullNameIdx = newFunc.GetNameStrIdx();
159 auto classNameIdx = newFunc.GetBaseClassNameStrIdx();
160 auto metaFullNameIdx = mirBuilder.GetOrCreateStringIndex(kFullNameStr);
161 auto metaClassNameIdx = mirBuilder.GetOrCreateStringIndex(kClassNameStr);
162 auto metaFuncNameIdx = mirBuilder.GetOrCreateStringIndex(kFuncNameStr);
163 MIRInfoVector &fnInfo = originalFunction.GetInfoVector();
164 const MapleVector<bool> &infoIsString = originalFunction.InfoIsString();
165 size_t size = fnInfo.size();
166 for (size_t i = 0; i < size; ++i) {
167 if (fnInfo[i].first == metaFullNameIdx) {
168 newFunc.PushbackMIRInfo(std::pair<GStrIdx, uint32>(fnInfo[i].first, fullNameIdx));
169 } else if (fnInfo[i].first == metaFuncNameIdx) {
170 newFunc.PushbackMIRInfo(std::pair<GStrIdx, uint32>(fnInfo[i].first, funcNameIdx));
171 } else if (fnInfo[i].first == metaClassNameIdx) {
172 newFunc.PushbackMIRInfo(std::pair<GStrIdx, uint32>(fnInfo[i].first, classNameIdx));
173 } else {
174 newFunc.PushbackMIRInfo(std::pair<GStrIdx, uint32>(fnInfo[i].first, fnInfo[i].second));
175 }
176 newFunc.PushbackIsString(infoIsString[i]);
177 }
178 }
179
UpdateFuncInfo(MIRFunction & newFunc)180 void Clone::UpdateFuncInfo(MIRFunction &newFunc)
181 {
182 auto fullNameIdx = newFunc.GetNameStrIdx();
183 auto metaFullNameIdx = mirBuilder.GetOrCreateStringIndex(kFullNameStr);
184 size_t size = newFunc.GetInfoVector().size();
185 for (size_t i = 0; i < size; ++i) {
186 if (newFunc.GetInfoPair(i).first == metaFullNameIdx) {
187 newFunc.SetMIRInfoNum(i, fullNameIdx);
188 break;
189 }
190 }
191 }
192
193 // Clone all functions that would be invoked with their return value ignored
194 // @param original_function The original function to be cloned
195 // @param mirBuilder A helper object
196 // @return Pointer to the newly cloned function
CloneFunctionNoReturn(MIRFunction & originalFunction)197 MIRFunction *Clone::CloneFunctionNoReturn(MIRFunction &originalFunction)
198 {
199 const std::string kNewMethodBaseName = replaceRetIgnored->GenerateNewBaseName(originalFunction);
200 MIRFunction *originalCurrFunction = mirBuilder.GetMirModule().CurFunction();
201 MIRFunction *newFunction =
202 CloneFunction(originalFunction, kNewMethodBaseName, GlobalTables::GetTypeTable().GetTypeFromTyIdx(1));
203
204 // new stmt should be located in the newFunction->codemp, mirBuilder.CreateStmtReturn will use CurFunction().codemp
205 // to assign space for the new stmt. So we set it correctly here.
206 mirBuilder.GetMirModule().SetCurFunction(newFunction);
207 if (originalFunction.GetBody() != nullptr) {
208 auto *body = newFunction->GetBody();
209 for (auto &stmt : body->GetStmtNodes()) {
210 if (stmt.GetOpCode() == OP_return) {
211 body->ReplaceStmt1WithStmt2(&stmt, mirBuilder.CreateStmtReturn(nullptr));
212 }
213 }
214 }
215 // setup new names for the newly cloned function
216 std::string newFuncFullName = replaceRetIgnored->GenerateNewFullName(originalFunction);
217 GStrIdx fullNameStrIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(newFuncFullName);
218 newFunction->OverrideBaseClassFuncNames(fullNameStrIdx);
219 MIRSymbol *funcSt = newFunction->GetFuncSymbol();
220 GlobalTables::GetGsymTable().RemoveFromStringSymbolMap(*funcSt);
221 funcSt->SetNameStrIdx(fullNameStrIdx);
222 GlobalTables::GetGsymTable().AddToStringSymbolMap(*funcSt);
223 UpdateFuncInfo(*newFunction);
224 mirBuilder.GetMirModule().SetCurFunction(originalCurrFunction);
225 return newFunction;
226 }
227
UpdateReturnVoidIfPossible(CallMeStmt * callMeStmt,const MIRFunction & targetFunc)228 void Clone::UpdateReturnVoidIfPossible(CallMeStmt *callMeStmt, const MIRFunction &targetFunc)
229 {
230 if (callMeStmt == nullptr) {
231 return;
232 }
233 if (replaceRetIgnored->ShouldReplaceWithVoidFunc(*callMeStmt, targetFunc) &&
234 replaceRetIgnored->IsInCloneList(targetFunc.GetName())) {
235 std::string funcNameReturnVoid = replaceRetIgnored->GenerateNewFullName(targetFunc);
236 GStrIdx gStrIdx = GlobalTables::GetStrTable().GetStrIdxFromName(funcNameReturnVoid);
237 MIRFunction *funcReturnVoid = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(gStrIdx)->GetFunction();
238 CHECK_FATAL(funcReturnVoid != nullptr, "target function not found at ssadevirtual");
239 callMeStmt->SetPUIdx(funcReturnVoid->GetPuidx());
240 }
241 }
242
DoClone()243 void Clone::DoClone()
244 {
245 std::set<std::string> clonedNewFuncMap;
246 for (const MapleString &funcName : *(replaceRetIgnored->GetTobeClonedFuncNames())) {
247 GStrIdx gStrIdx = GlobalTables::GetStrTable().GetStrIdxFromName(std::string(funcName.c_str()));
248 MIRSymbol *symbol = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(gStrIdx);
249 if (symbol != nullptr) {
250 GStrIdx gStrIdxOfFunc = GlobalTables::GetStrTable().GetStrIdxFromName(std::string(funcName.c_str()));
251 MIRFunction *oriFunc = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(gStrIdxOfFunc)->GetFunction();
252 mirModule->SetCurFunction(oriFunc);
253 (void)clonedNewFuncMap.insert(CloneFunctionNoReturn(*oriFunc)->GetName());
254 }
255 }
256 }
257
258 } // namespace maple
259