• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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