• 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     DEBUG_ASSERT(newFunc->GetFuncSymbol() != nullptr, "nullpt check");
129     classType->GetMethods().push_back(MethodPair(
130         newFunc->GetStIdx(), TyidxFuncAttrPair(newFunc->GetFuncSymbol()->GetTyIdx(), originalFunction.GetFuncAttrs())));
131     newFunc->SetFlag(originalFunction.GetFlag());
132     newFunc->SetSrcPosition(originalFunction.GetSrcPosition());
133     newFunc->SetFuncAttrs(originalFunction.GetFuncAttrs());
134     newFunc->SetBaseClassFuncNames(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(fullName));
135     if (originalFunction.GetBody() != nullptr) {
136         CopyFuncInfo(originalFunction, *newFunc);
137         MIRFunction *originalCurrFunction = mirBuilder.GetCurrentFunctionNotNull();
138         mirBuilder.SetCurrentFunction(*newFunc);
139         newFunc->SetBody(
140             originalFunction.GetBody()->CloneTree(originalFunction.GetModule()->GetCurFuncCodeMPAllocator()));
141         CloneSymbols(*newFunc, originalFunction);
142         CloneLabels(*newFunc, originalFunction);
143         mirBuilder.SetCurrentFunction(*originalCurrFunction);
144     }
145     return newFunc;
146 }
147 
CloneArgument(MIRFunction & originalFunction,ArgVector & argument) const148 void Clone::CloneArgument(MIRFunction &originalFunction, ArgVector &argument) const
149 {
150     for (size_t i = 0; i < originalFunction.GetFormalCount(); ++i) {
151         auto &formalName = originalFunction.GetFormalName(i);
152         argument.push_back(ArgPair(formalName, originalFunction.GetNthParamType(i)));
153     }
154 }
155 
CopyFuncInfo(MIRFunction & originalFunction,MIRFunction & newFunc) const156 void Clone::CopyFuncInfo(MIRFunction &originalFunction, MIRFunction &newFunc) const
157 {
158     auto funcNameIdx = newFunc.GetBaseFuncNameStrIdx();
159     auto fullNameIdx = newFunc.GetNameStrIdx();
160     auto classNameIdx = newFunc.GetBaseClassNameStrIdx();
161     auto metaFullNameIdx = mirBuilder.GetOrCreateStringIndex(kFullNameStr);
162     auto metaClassNameIdx = mirBuilder.GetOrCreateStringIndex(kClassNameStr);
163     auto metaFuncNameIdx = mirBuilder.GetOrCreateStringIndex(kFuncNameStr);
164     MIRInfoVector &fnInfo = originalFunction.GetInfoVector();
165     const MapleVector<bool> &infoIsString = originalFunction.InfoIsString();
166     size_t size = fnInfo.size();
167     for (size_t i = 0; i < size; ++i) {
168         if (fnInfo[i].first == metaFullNameIdx) {
169             newFunc.PushbackMIRInfo(std::pair<GStrIdx, uint32>(fnInfo[i].first, fullNameIdx));
170         } else if (fnInfo[i].first == metaFuncNameIdx) {
171             newFunc.PushbackMIRInfo(std::pair<GStrIdx, uint32>(fnInfo[i].first, funcNameIdx));
172         } else if (fnInfo[i].first == metaClassNameIdx) {
173             newFunc.PushbackMIRInfo(std::pair<GStrIdx, uint32>(fnInfo[i].first, classNameIdx));
174         } else {
175             newFunc.PushbackMIRInfo(std::pair<GStrIdx, uint32>(fnInfo[i].first, fnInfo[i].second));
176         }
177         newFunc.PushbackIsString(infoIsString[i]);
178     }
179 }
180 
UpdateFuncInfo(MIRFunction & newFunc)181 void Clone::UpdateFuncInfo(MIRFunction &newFunc)
182 {
183     auto fullNameIdx = newFunc.GetNameStrIdx();
184     auto metaFullNameIdx = mirBuilder.GetOrCreateStringIndex(kFullNameStr);
185     size_t size = newFunc.GetInfoVector().size();
186     for (size_t i = 0; i < size; ++i) {
187         if (newFunc.GetInfoPair(i).first == metaFullNameIdx) {
188             newFunc.SetMIRInfoNum(i, fullNameIdx);
189             break;
190         }
191     }
192 }
193 
194 // Clone all functions that would be invoked with their return value ignored
195 // @param original_function The original function to be cloned
196 // @param mirBuilder A helper object
197 // @return Pointer to the newly cloned function
CloneFunctionNoReturn(MIRFunction & originalFunction)198 MIRFunction *Clone::CloneFunctionNoReturn(MIRFunction &originalFunction)
199 {
200     const std::string kNewMethodBaseName = replaceRetIgnored->GenerateNewBaseName(originalFunction);
201     MIRFunction *originalCurrFunction = mirBuilder.GetMirModule().CurFunction();
202     MIRFunction *newFunction =
203         CloneFunction(originalFunction, kNewMethodBaseName, GlobalTables::GetTypeTable().GetTypeFromTyIdx(1));
204 
205     // new stmt should be located in the newFunction->codemp, mirBuilder.CreateStmtReturn will use CurFunction().codemp
206     // to assign space for the new stmt. So we set it correctly here.
207     mirBuilder.GetMirModule().SetCurFunction(newFunction);
208     if (originalFunction.GetBody() != nullptr) {
209         auto *body = newFunction->GetBody();
210         for (auto &stmt : body->GetStmtNodes()) {
211             if (stmt.GetOpCode() == OP_return) {
212                 body->ReplaceStmt1WithStmt2(&stmt, mirBuilder.CreateStmtReturn(nullptr));
213             }
214         }
215     }
216     // setup new names for the newly cloned function
217     std::string newFuncFullName = replaceRetIgnored->GenerateNewFullName(originalFunction);
218     GStrIdx fullNameStrIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(newFuncFullName);
219     newFunction->OverrideBaseClassFuncNames(fullNameStrIdx);
220     MIRSymbol *funcSt = newFunction->GetFuncSymbol();
221     DEBUG_ASSERT(funcSt != nullptr, "nullptr check");
222     GlobalTables::GetGsymTable().RemoveFromStringSymbolMap(*funcSt);
223     funcSt->SetNameStrIdx(fullNameStrIdx);
224     GlobalTables::GetGsymTable().AddToStringSymbolMap(*funcSt);
225     UpdateFuncInfo(*newFunction);
226     mirBuilder.GetMirModule().SetCurFunction(originalCurrFunction);
227     return newFunction;
228 }
229 
UpdateReturnVoidIfPossible(CallMeStmt * callMeStmt,const MIRFunction & targetFunc)230 void Clone::UpdateReturnVoidIfPossible(CallMeStmt *callMeStmt, const MIRFunction &targetFunc)
231 {
232     if (callMeStmt == nullptr) {
233         return;
234     }
235     if (replaceRetIgnored->ShouldReplaceWithVoidFunc(*callMeStmt, targetFunc) &&
236         replaceRetIgnored->IsInCloneList(targetFunc.GetName())) {
237         std::string funcNameReturnVoid = replaceRetIgnored->GenerateNewFullName(targetFunc);
238         GStrIdx gStrIdx = GlobalTables::GetStrTable().GetStrIdxFromName(funcNameReturnVoid);
239         DEBUG_ASSERT(GlobalTables::GetGsymTable().GetSymbolFromStrIdx(gStrIdx) != nullptr,
240             "nullptr check");
241         MIRFunction *funcReturnVoid = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(gStrIdx)->GetFunction();
242         CHECK_FATAL(funcReturnVoid != nullptr, "target function not found at ssadevirtual");
243         callMeStmt->SetPUIdx(funcReturnVoid->GetPuidx());
244     }
245 }
246 
247 }  // namespace maple
248