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 "mir_module.h"
17 #include "mir_const.h"
18 #include "mir_preg.h"
19 #include "mir_function.h"
20 #include "mir_builder.h"
21 #include "debug_info.h"
22 #include "intrinsics.h"
23 #include "bin_mplt.h"
24
25 namespace maple {
26 #if MIR_FEATURE_FULL // to avoid compilation error when MIR_FEATURE_FULL=0
MIRModule(const std::string & fn)27 MIRModule::MIRModule(const std::string &fn)
28 : memPool(new ThreadShareMemPool(memPoolCtrler, "maple_ir mempool")),
29 pragmaMemPool(memPoolCtrler.NewMemPool("pragma mempool", false /* isLcalPool */)),
30 memPoolAllocator(memPool),
31 pragmaMemPoolAllocator(pragmaMemPool),
32 functionList(memPoolAllocator.Adapter()),
33 importedMplt(memPoolAllocator.Adapter()),
34 typeDefOrder(memPoolAllocator.Adapter()),
35 externStructTypeSet(std::less<TyIdx>(), memPoolAllocator.Adapter()),
36 symbolSet(std::less<StIdx>(), memPoolAllocator.Adapter()),
37 symbolDefOrder(memPoolAllocator.Adapter()),
38 out(LogInfo::MapleLogger()),
39 fileName(fn),
40 fileInfo(memPoolAllocator.Adapter()),
41 fileInfoIsString(memPoolAllocator.Adapter()),
42 fileData(memPoolAllocator.Adapter()),
43 srcFileInfo(memPoolAllocator.Adapter()),
44 importFiles(memPoolAllocator.Adapter()),
45 importPaths(memPoolAllocator.Adapter()),
46 asmDecls(memPoolAllocator.Adapter()),
47 classList(memPoolAllocator.Adapter()),
48 optimizedFuncs(memPoolAllocator.Adapter()),
49 optimizedFuncsType(memPoolAllocator.Adapter()),
50 puIdxFieldInitializedMap(std::less<PUIdx>(), memPoolAllocator.Adapter()),
51 inliningGlobals(memPoolAllocator.Adapter()),
52 partO2FuncList(memPoolAllocator.Adapter()),
53 safetyWarningMap(memPoolAllocator.Adapter())
54 {
55 GlobalTables::GetGsymTable().SetModule(this);
56 typeNameTab = memPool->New<MIRTypeNameTable>(memPoolAllocator);
57 mirBuilder = memPool->New<MIRBuilder>(this);
58 dbgInfo = memPool->New<DebugInfo>(this);
59 IntrinDesc::InitMIRModule(this);
60 }
61
~MIRModule()62 MIRModule::~MIRModule()
63 {
64 for (MIRFunction *mirFunc : functionList) {
65 mirFunc->ReleaseCodeMemory();
66 }
67 ReleasePragmaMemPool();
68 delete memPool;
69 delete binMplt;
70 }
71
CurFuncCodeMemPool() const72 MemPool *MIRModule::CurFuncCodeMemPool() const
73 {
74 if (useFuncCodeMemPoolTmp) {
75 return CurFunction()->GetCodeMemPoolTmp();
76 }
77 return CurFunction()->GetCodeMemPool();
78 }
79
CurFuncCodeMemPoolAllocator() const80 MapleAllocator *MIRModule::CurFuncCodeMemPoolAllocator() const
81 {
82 MIRFunction *curFunc = CurFunction();
83 CHECK_FATAL(curFunc != nullptr, "curFunction is null");
84 return &curFunc->GetCodeMempoolAllocator();
85 }
86
GetCurFuncCodeMPAllocator() const87 MapleAllocator &MIRModule::GetCurFuncCodeMPAllocator() const
88 {
89 MIRFunction *curFunc = CurFunction();
90 CHECK_FATAL(curFunc != nullptr, "curFunction is null");
91 return curFunc->GetCodeMPAllocator();
92 }
93
AddExternStructType(TyIdx tyIdx)94 void MIRModule::AddExternStructType(TyIdx tyIdx)
95 {
96 (void)externStructTypeSet.insert(tyIdx);
97 }
98
AddExternStructType(const MIRType * t)99 void MIRModule::AddExternStructType(const MIRType *t)
100 {
101 DEBUG_ASSERT(t != nullptr, "MIRType is null");
102 (void)externStructTypeSet.insert(t->GetTypeIndex());
103 }
104
AddSymbol(StIdx stIdx)105 void MIRModule::AddSymbol(StIdx stIdx)
106 {
107 auto it = symbolSet.find(stIdx);
108 if (it == symbolSet.end()) {
109 symbolDefOrder.push_back(stIdx);
110 }
111 (void)symbolSet.insert(stIdx);
112 }
113
AddSymbol(const MIRSymbol * s)114 void MIRModule::AddSymbol(const MIRSymbol *s)
115 {
116 DEBUG_ASSERT(s != nullptr, "s is null");
117 AddSymbol(s->GetStIdx());
118 }
119
DumpGlobals(bool emitStructureType) const120 void MIRModule::DumpGlobals(bool emitStructureType) const
121 {
122 if (flavor != kFlavorUnknown) {
123 LogInfo::MapleLogger() << "flavor " << flavor << '\n';
124 }
125 if (srcLang != kSrcLangUnknown) {
126 LogInfo::MapleLogger() << "srclang " << srcLang << '\n';
127 }
128 LogInfo::MapleLogger() << "id " << id << '\n';
129 if (globalMemSize != 0) {
130 LogInfo::MapleLogger() << "globalmemsize " << globalMemSize << '\n';
131 }
132 if (globalBlkMap != nullptr) {
133 LogInfo::MapleLogger() << "globalmemmap = [ ";
134 auto *p = reinterpret_cast<uint32 *>(globalBlkMap);
135 LogInfo::MapleLogger() << std::hex;
136 while (p < reinterpret_cast<uint32 *>(globalBlkMap + globalMemSize)) {
137 LogInfo::MapleLogger() << std::hex << "0x" << *p << " ";
138 p++;
139 }
140 LogInfo::MapleLogger() << std::dec << "]\n";
141 }
142 if (globalWordsTypeTagged != nullptr) {
143 LogInfo::MapleLogger() << "globalwordstypetagged = [ ";
144 auto *p = reinterpret_cast<uint32 *>(globalWordsTypeTagged);
145 LogInfo::MapleLogger() << std::hex;
146 while (p < reinterpret_cast<uint32 *>(globalWordsTypeTagged + BlockSize2BitVectorSize(globalMemSize))) {
147 LogInfo::MapleLogger() << std::hex << "0x" << *p << " ";
148 ++p;
149 }
150 LogInfo::MapleLogger() << std::dec << "]\n";
151 }
152 if (globalWordsRefCounted != nullptr) {
153 LogInfo::MapleLogger() << "globalwordsrefcounted = [ ";
154 auto *p = reinterpret_cast<uint32 *>(globalWordsRefCounted);
155 LogInfo::MapleLogger() << std::hex;
156 while (p < reinterpret_cast<uint32 *>(globalWordsRefCounted + BlockSize2BitVectorSize(globalMemSize))) {
157 LogInfo::MapleLogger() << std::hex << "0x" << *p << " ";
158 ++p;
159 }
160 LogInfo::MapleLogger() << std::dec << "]\n";
161 }
162 LogInfo::MapleLogger() << "numfuncs " << numFuncs << '\n';
163 if (!importFiles.empty()) {
164 // Output current module's mplt on top, imported ones at below
165 for (auto it = importFiles.rbegin(); it != importFiles.rend(); ++it) {
166 LogInfo::MapleLogger() << "import \"" << GlobalTables::GetStrTable().GetStringFromStrIdx(*it) << "\"\n";
167 }
168 }
169 if (!importPaths.empty()) {
170 size_t size = importPaths.size();
171 for (size_t i = 0; i < size; ++i) {
172 LogInfo::MapleLogger() << "importpath \"" << GlobalTables::GetStrTable().GetStringFromStrIdx(importPaths[i])
173 << "\"\n";
174 }
175 }
176 if (!asmDecls.empty()) {
177 size_t size = asmDecls.size();
178 for (size_t i = 0; i < size; ++i) {
179 LogInfo::MapleLogger() << "asmdecl ";
180 EmitStr(asmDecls[i]);
181 }
182 }
183 if (entryFuncName.length()) {
184 LogInfo::MapleLogger() << "entryfunc &" << entryFuncName << '\n';
185 }
186 if (!fileInfo.empty()) {
187 LogInfo::MapleLogger() << "fileinfo {\n";
188 size_t size = fileInfo.size();
189 for (size_t i = 0; i < size; ++i) {
190 LogInfo::MapleLogger() << " @" << GlobalTables::GetStrTable().GetStringFromStrIdx(fileInfo[i].first)
191 << " ";
192 if (!fileInfoIsString[i]) {
193 LogInfo::MapleLogger() << "0x" << std::hex << fileInfo[i].second;
194 } else {
195 LogInfo::MapleLogger() << "\""
196 << GlobalTables::GetStrTable().GetStringFromStrIdx(GStrIdx(fileInfo[i].second))
197 << "\"";
198 }
199 if (i < size - 1) {
200 LogInfo::MapleLogger() << ",\n";
201 } else {
202 LogInfo::MapleLogger() << "}\n";
203 }
204 }
205 LogInfo::MapleLogger() << std::dec;
206 }
207 if (!srcFileInfo.empty()) {
208 LogInfo::MapleLogger() << "srcfileinfo {\n";
209 size_t size = srcFileInfo.size();
210 size_t i = 0;
211 for (auto infoElem : srcFileInfo) {
212 LogInfo::MapleLogger() << " " << infoElem.second;
213 LogInfo::MapleLogger() << " \"" << GlobalTables::GetStrTable().GetStringFromStrIdx(infoElem.first) << "\"";
214 if (i++ < size - 1) {
215 LogInfo::MapleLogger() << ",\n";
216 } else {
217 LogInfo::MapleLogger() << "}\n";
218 }
219 }
220 }
221 if (!fileData.empty()) {
222 LogInfo::MapleLogger() << "filedata {\n";
223 size_t size = fileData.size();
224 for (size_t i = 0; i < size; ++i) {
225 LogInfo::MapleLogger() << " @" << GlobalTables::GetStrTable().GetStringFromStrIdx(fileData[i].first)
226 << " ";
227 size_t dataSize = fileData[i].second.size();
228 for (size_t j = 0; j < dataSize; ++j) {
229 uint8 data = fileData[i].second[j];
230 LogInfo::MapleLogger() << "0x" << std::hex << static_cast<uint32>(data);
231 if (j < dataSize - 1) {
232 LogInfo::MapleLogger() << ' ';
233 }
234 }
235 if (i < size - 1) {
236 LogInfo::MapleLogger() << ",\n";
237 } else {
238 LogInfo::MapleLogger() << "}\n";
239 }
240 }
241 LogInfo::MapleLogger() << std::dec;
242 }
243 if (flavor < kMmpl || flavor == kFlavorLmbc) {
244 for (auto it = typeDefOrder.begin(); it != typeDefOrder.end(); ++it) {
245 TyIdx tyIdx = typeNameTab->GetTyIdxFromGStrIdx(*it);
246 const std::string &name = GlobalTables::GetStrTable().GetStringFromStrIdx(*it);
247 MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx);
248 DEBUG_ASSERT(type != nullptr, "type should not be nullptr here");
249 bool isStructType = type->IsStructType();
250 if (isStructType) {
251 auto *structType = static_cast<MIRStructType *>(type);
252 // still emit what in extern_structtype_set_
253 if (!emitStructureType &&
254 externStructTypeSet.find(structType->GetTypeIndex()) == externStructTypeSet.end()) {
255 continue;
256 }
257 if (structType->IsImported()) {
258 continue;
259 }
260 }
261
262 LogInfo::MapleLogger() << "type $" << name << " ";
263 if (type->GetKind() == kTypeByName) {
264 LogInfo::MapleLogger() << "void";
265 } else if (type->GetNameStrIdx() == *it) {
266 type->Dump(1, true);
267 } else {
268 type->Dump(1);
269 }
270 LogInfo::MapleLogger() << '\n';
271 }
272 if (someSymbolNeedForwDecl) {
273 // an extra pass thru the global symbol table to print forward decl
274 for (auto sit = symbolSet.begin(); sit != symbolSet.end(); ++sit) {
275 MIRSymbol *s = GlobalTables::GetGsymTable().GetSymbolFromStidx((*sit).Idx());
276 if (s->IsNeedForwDecl()) {
277 s->Dump(false, 0, true);
278 }
279 }
280 }
281 // dump javaclass and javainterface first
282 for (auto sit = symbolDefOrder.begin(); sit != symbolDefOrder.end(); ++sit) {
283 MIRSymbol *s = GlobalTables::GetGsymTable().GetSymbolFromStidx((*sit).Idx());
284 DEBUG_ASSERT(s != nullptr, "null ptr check");
285 if (!s->IsJavaClassInterface()) {
286 continue;
287 }
288 // Verify: all wpofake variables should have been deleted from globaltable
289 if (!s->IsDeleted()) {
290 s->Dump(false, 0);
291 }
292 }
293 for (auto sit = symbolDefOrder.begin(); sit != symbolDefOrder.end(); ++sit) {
294 MIRSymbol *s = GlobalTables::GetGsymTable().GetSymbolFromStidx((*sit).Idx());
295 CHECK_FATAL(s != nullptr, "nullptr check");
296 if (s->IsJavaClassInterface()) {
297 continue;
298 }
299 if (!s->IsDeleted() && !s->GetIsImported() && !s->GetIsImportedDecl()) {
300 s->Dump(false, 0);
301 }
302 }
303 }
304 }
305
Dump(bool emitStructureType,const std::unordered_set<std::string> * dumpFuncSet) const306 void MIRModule::Dump(bool emitStructureType, const std::unordered_set<std::string> *dumpFuncSet) const
307 {
308 DumpGlobals(emitStructureType);
309 DumpFunctionList(dumpFuncSet);
310 }
311
DumpGlobalArraySymbol() const312 void MIRModule::DumpGlobalArraySymbol() const
313 {
314 for (StIdx stIdx : symbolSet) {
315 MIRSymbol *symbol = GlobalTables::GetGsymTable().GetSymbolFromStidx(stIdx.Idx());
316 DEBUG_ASSERT(symbol != nullptr, "null ptr check");
317 MIRType *symbolType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(symbol->GetTyIdx());
318 DEBUG_ASSERT(symbolType != nullptr, "null ptr check");
319 if (symbolType == nullptr || symbolType->GetKind() != kTypeArray) {
320 continue;
321 }
322 symbol->Dump(false, 0);
323 }
324 }
325
Emit(const std::string & outFileName) const326 void MIRModule::Emit(const std::string &outFileName) const
327 {
328 std::ofstream file;
329 // Change cout's buffer to file.
330 std::streambuf *backup = LogInfo::MapleLogger().rdbuf();
331 LogInfo::MapleLogger().rdbuf(file.rdbuf());
332 file.open(outFileName, std::ios::trunc);
333 DumpGlobals();
334 for (MIRFunction *mirFunc : functionList) {
335 mirFunc->Dump();
336 }
337 // Restore cout's buffer.
338 LogInfo::MapleLogger().rdbuf(backup);
339 file.close();
340 }
341
DumpFunctionList(const std::unordered_set<std::string> * dumpFuncSet) const342 void MIRModule::DumpFunctionList(const std::unordered_set<std::string> *dumpFuncSet) const
343 {
344 for (MIRFunction *mirFunc : functionList) {
345 if (dumpFuncSet == nullptr || dumpFuncSet->empty()) {
346 mirFunc->Dump();
347 } else { // dump only if this func matches any name in *dumpFuncSet
348 const std::string &name = mirFunc->GetName();
349 bool matched = false;
350 for (std::string elem : *dumpFuncSet) {
351 if (name.find(elem.c_str()) != std::string::npos) {
352 matched = true;
353 break;
354 }
355 }
356 if (matched) {
357 mirFunc->Dump();
358 }
359 }
360 }
361 }
362
OutputFunctionListAsciiMpl(const std::string & phaseName)363 void MIRModule::OutputFunctionListAsciiMpl(const std::string &phaseName)
364 {
365 std::string fileStem;
366 std::string::size_type lastDot = fileName.find_last_of('.');
367 if (lastDot == std::string::npos) {
368 fileStem = fileName.append(phaseName);
369 } else {
370 fileStem = fileName.substr(0, lastDot).append(phaseName);
371 }
372 std::string outfileName;
373 if (flavor >= kMmpl) {
374 outfileName = fileStem.append(".mmpl");
375 } else {
376 outfileName = fileStem.append(".mpl");
377 }
378 std::ofstream mplFile;
379 mplFile.open(outfileName, std::ios::app);
380 std::streambuf *backup = LogInfo::MapleLogger().rdbuf();
381 LogInfo::MapleLogger().rdbuf(mplFile.rdbuf()); // change cout's buffer to that of file
382 DumpGlobalArraySymbol();
383 DumpFunctionList(nullptr);
384 LogInfo::MapleLogger().rdbuf(backup); // restore cout's buffer
385 mplFile.close();
386 }
387
DumpToFile(const std::string & fileNameStr,bool emitStructureType) const388 void MIRModule::DumpToFile(const std::string &fileNameStr, bool emitStructureType) const
389 {
390 std::ofstream file;
391 file.open(fileNameStr, std::ios::trunc);
392 if (!file.is_open()) {
393 ERR(kLncErr, "Cannot open %s", fileNameStr.c_str());
394 return;
395 }
396 // Change cout's buffer to file.
397 std::streambuf *backup = LogInfo::MapleLogger().rdbuf();
398 LogInfo::MapleLogger().rdbuf(file.rdbuf());
399 Dump(emitStructureType);
400 // Restore cout's buffer.
401 LogInfo::MapleLogger().rdbuf(backup);
402 file.close();
403 }
404
DumpDefType()405 void MIRModule::DumpDefType()
406 {
407 for (auto it = typeDefOrder.begin(); it != typeDefOrder.end(); ++it) {
408 TyIdx tyIdx = typeNameTab->GetTyIdxFromGStrIdx(*it);
409 const std::string &name = GlobalTables::GetStrTable().GetStringFromStrIdx(*it);
410 MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx);
411 DEBUG_ASSERT(type != nullptr, "type should not be nullptr here");
412 bool isStructType = type->IsStructType();
413 if (isStructType) {
414 auto *structType = static_cast<MIRStructType *>(type);
415 if (structType->IsImported()) {
416 continue;
417 }
418 }
419 LogInfo::MapleLogger() << "type $" << name << " ";
420 if (type->GetKind() == kTypeByName) {
421 LogInfo::MapleLogger() << "void";
422 } else if (type->GetNameStrIdx() == *it) {
423 type->Dump(1, true);
424 } else {
425 type->Dump(1);
426 }
427 LogInfo::MapleLogger() << '\n';
428 }
429 }
430
DumpInlineCandidateToFile(const std::string & fileNameStr)431 void MIRModule::DumpInlineCandidateToFile(const std::string &fileNameStr)
432 {
433 if (optimizedFuncs.empty()) {
434 return;
435 }
436 std::ofstream file;
437 // Change cout's buffer to file.
438 std::streambuf *backup = LogInfo::MapleLogger().rdbuf();
439 LogInfo::MapleLogger().rdbuf(file.rdbuf());
440 file.open(fileNameStr, std::ios::trunc);
441 if (IsCModule()) {
442 DumpDefType();
443 }
444 // dump global variables needed for inlining file
445 for (auto symbolIdx : inliningGlobals) {
446 MIRSymbol *s = GlobalTables::GetGsymTable().GetSymbolFromStidx(symbolIdx);
447 DEBUG_ASSERT(s != nullptr, "null ptr check");
448 if (s->GetStorageClass() == kScFstatic) {
449 if (s->IsNeedForwDecl()) {
450 // const string, including initialization
451 s->Dump(false, 0, false);
452 }
453 }
454 }
455 for (auto symbolIdx : inliningGlobals) {
456 MIRSymbol *s = GlobalTables::GetGsymTable().GetSymbolFromStidx(symbolIdx);
457 DEBUG_ASSERT(s != nullptr, "null ptr check");
458 MIRStorageClass sc = s->GetStorageClass();
459 if (s->GetStorageClass() == kScFstatic) {
460 if (!s->IsNeedForwDecl()) {
461 // const string, including initialization
462 s->Dump(false, 0, false);
463 }
464 } else if (s->GetSKind() == kStFunc) {
465 s->GetFunction()->Dump(true);
466 } else {
467 // static fields as extern
468 s->SetStorageClass(kScExtern);
469 s->Dump(false, 0, true);
470 }
471 s->SetStorageClass(sc);
472 }
473 for (auto *func : optimizedFuncs) {
474 func->SetWithLocInfo(false);
475 func->Dump();
476 }
477 // Restore cout's buffer.
478 LogInfo::MapleLogger().rdbuf(backup);
479 file.close();
480 }
481
482 // This is not efficient. Only used in debug mode for now.
GetFileNameFromFileNum(uint32 fileNum) const483 const std::string &MIRModule::GetFileNameFromFileNum(uint32 fileNum) const
484 {
485 GStrIdx nameIdx(0);
486 for (auto &info : srcFileInfo) {
487 if (info.second == fileNum) {
488 nameIdx = info.first;
489 break;
490 }
491 }
492 return GlobalTables::GetStrTable().GetStringFromStrIdx(nameIdx);
493 }
494
DumpToHeaderFile(bool binaryMplt,const std::string & outputName)495 void MIRModule::DumpToHeaderFile(bool binaryMplt, const std::string &outputName)
496 {
497 std::string outfileName;
498 std::string fileNameLocal = !outputName.empty() ? outputName : fileName;
499 std::string::size_type lastDot = fileNameLocal.find_last_of('.');
500 if (lastDot == std::string::npos) {
501 outfileName = fileNameLocal.append(".mplt");
502 } else {
503 outfileName = fileNameLocal.substr(0, lastDot).append(".mplt");
504 }
505 if (binaryMplt) {
506 BinaryMplt binaryMpltTmp(*this);
507 binaryMpltTmp.Export(outfileName);
508 } else {
509 std::ofstream mpltFile;
510 mpltFile.open(outfileName, std::ios::trunc);
511 std::streambuf *backup = LogInfo::MapleLogger().rdbuf();
512 LogInfo::MapleLogger().rdbuf(mpltFile.rdbuf()); // change cout's buffer to that of file
513 for (std::pair<std::u16string, MIRSymbol *> entity : GlobalTables::GetConstPool().GetConstU16StringPool()) {
514 LogInfo::MapleLogger() << "var $";
515 entity.second->DumpAsLiteralVar();
516 LogInfo::MapleLogger() << '\n';
517 }
518 for (auto it = classList.begin(); it != classList.end(); ++it) {
519 TyIdx curTyIdx(*it);
520 MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(curTyIdx);
521 const std::string &name = GlobalTables::GetStrTable().GetStringFromStrIdx(type->GetNameStrIdx());
522 if (type->GetKind() == kTypeClass || type->GetKind() == kTypeInterface) {
523 auto *structType = static_cast<MIRStructType *>(type);
524 // skip imported class/interface and incomplete types
525 if (!structType->IsImported() && !structType->IsIncomplete()) {
526 LogInfo::MapleLogger() << "type $" << name << " ";
527 type->Dump(1, true);
528 LogInfo::MapleLogger() << '\n';
529 }
530 }
531 }
532 /* restore cout */
533 LogInfo::MapleLogger().rdbuf(backup);
534 mpltFile.close();
535 }
536 }
537
538 /*
539 We use MIRStructType (kTypeStruct) to represent C/C++ structs
540 as well as C++ classes.
541
542 We use MIRClassType (kTypeClass) to represent Java classes, specifically.
543 MIRClassType has parents which encode Java class's parent (exploiting
544 the fact Java classes have at most one parent class.
545 */
DumpTypeTreeToCxxHeaderFile(MIRType & ty,std::unordered_set<MIRType * > & dumpedClasses) const546 void MIRModule::DumpTypeTreeToCxxHeaderFile(MIRType &ty, std::unordered_set<MIRType *> &dumpedClasses) const
547 {
548 if (dumpedClasses.find(&ty) != dumpedClasses.end()) {
549 return;
550 }
551 // first, insert ty to the dumped_classes to prevent infinite recursion
552 (void)dumpedClasses.insert(&ty);
553 DEBUG_ASSERT(ty.GetKind() == kTypeClass || ty.GetKind() == kTypeStruct || ty.GetKind() == kTypeUnion ||
554 ty.GetKind() == kTypeInterface,
555 "Unexpected MIRType.");
556 /* No need to emit interfaces; because "interface variables are
557 final and static by default and methods are public and abstract"
558 */
559 if (ty.GetKind() == kTypeInterface) {
560 return;
561 }
562 // dump all of its parents
563 if (IsJavaModule()) {
564 DEBUG_ASSERT(ty.GetKind() != kTypeStruct, "type is not supposed to be struct");
565 DEBUG_ASSERT(ty.GetKind() != kTypeUnion, "type is not supposed to be union");
566 DEBUG_ASSERT(ty.GetKind() != kTypeInterface, "type is not supposed to be interface");
567 } else if (srcLang == kSrcLangC || srcLang == kSrcLangCPlusPlus) {
568 DEBUG_ASSERT((ty.GetKind() == kTypeStruct || ty.GetKind() == kTypeUnion),
569 "type should be either struct or union");
570 } else {
571 DEBUG_ASSERT(false, "source languages other than C/C++ are not supported yet");
572 }
573 const std::string &name = GlobalTables::GetStrTable().GetStringFromStrIdx(ty.GetNameStrIdx());
574 if (IsJavaModule()) {
575 // Java class has at most one parent
576 auto &classType = static_cast<MIRClassType &>(ty);
577 MIRClassType *parentType = nullptr;
578 // find parent and generate its type as well as those of its ancestors
579 if (classType.GetParentTyIdx() != 0u /* invalid type idx */) {
580 parentType =
581 static_cast<MIRClassType *>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(classType.GetParentTyIdx()));
582 CHECK_FATAL(parentType != nullptr, "nullptr check");
583 DumpTypeTreeToCxxHeaderFile(*parentType, dumpedClasses);
584 }
585 LogInfo::MapleLogger() << "struct " << name << " ";
586 if (parentType != nullptr) {
587 LogInfo::MapleLogger() << ": " << parentType->GetName() << " ";
588 }
589 if (!classType.IsIncomplete()) {
590 /* dump class type; it will dump as '{ ... }' */
591 classType.DumpAsCxx(1);
592 LogInfo::MapleLogger() << ";\n";
593 } else {
594 LogInfo::MapleLogger() << " /* incomplete type */\n";
595 }
596 } else if (srcLang == kSrcLangC || srcLang == kSrcLangCPlusPlus) {
597 // how to access parent fields????
598 DEBUG_ASSERT(false, "not yet implemented");
599 }
600 }
601
DumpToCxxHeaderFile(std::set<std::string> & leafClasses,const std::string & pathToOutf) const602 void MIRModule::DumpToCxxHeaderFile(std::set<std::string> &leafClasses, const std::string &pathToOutf) const
603 {
604 std::ofstream mpltFile;
605 mpltFile.open(pathToOutf, std::ios::trunc);
606 std::streambuf *backup = LogInfo::MapleLogger().rdbuf();
607 LogInfo::MapleLogger().rdbuf(mpltFile.rdbuf()); // change cout's buffer to that of file
608 char *headerGuard = strdup(pathToOutf.c_str());
609 CHECK_FATAL(headerGuard != nullptr, "strdup failed");
610 for (char *p = headerGuard; *p; ++p) {
611 if (!isalnum(*p)) {
612 *p = '_';
613 } else if (isalpha(*p) && islower(*p)) {
614 *p = toupper(*p);
615 }
616 }
617 // define a hash table
618 std::unordered_set<MIRType *> dumpedClasses;
619 const char *prefix = "__SRCLANG_UNKNOWN_";
620 if (IsJavaModule()) {
621 prefix = "__SRCLANG_JAVA_";
622 } else if (srcLang == kSrcLangC || srcLang == kSrcLangCPlusPlus) {
623 prefix = "__SRCLANG_CXX_";
624 }
625 LogInfo::MapleLogger() << "#ifndef " << prefix << headerGuard << "__\n";
626 LogInfo::MapleLogger() << "#define " << prefix << headerGuard << "__\n";
627 LogInfo::MapleLogger() << "/* this file is compiler-generated; do not edit */\n\n";
628 LogInfo::MapleLogger() << "#include <stdint.h>\n";
629 LogInfo::MapleLogger() << "#include <complex.h>\n";
630 for (auto &s : leafClasses) {
631 CHECK_FATAL(!s.empty(), "string is null");
632 GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(s);
633 TyIdx tyIdx = typeNameTab->GetTyIdxFromGStrIdx(strIdx);
634 MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx);
635 if (ty == nullptr) {
636 continue;
637 }
638 DEBUG_ASSERT(ty->GetKind() == kTypeClass || ty->GetKind() == kTypeStruct || ty->GetKind() == kTypeUnion ||
639 ty->GetKind() == kTypeInterface,
640 "");
641 DumpTypeTreeToCxxHeaderFile(*ty, dumpedClasses);
642 }
643 LogInfo::MapleLogger() << "#endif /* " << prefix << headerGuard << "__ */\n";
644 /* restore cout */
645 LogInfo::MapleLogger().rdbuf(backup);
646 free(headerGuard);
647 headerGuard = nullptr;
648 mpltFile.close();
649 }
650
DumpClassToFile(const std::string & path) const651 void MIRModule::DumpClassToFile(const std::string &path) const
652 {
653 std::string strPath(path);
654 strPath.append("/");
655 for (auto it : typeNameTab->GetGStrIdxToTyIdxMap()) {
656 const std::string &name = GlobalTables::GetStrTable().GetStringFromStrIdx(it.first);
657 MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(it.second);
658 std::string outClassFile(name);
659 /* replace class name / with - */
660 std::replace(outClassFile.begin(), outClassFile.end(), '/', '-');
661 (void)outClassFile.insert(0, strPath);
662 outClassFile.append(".mpl");
663 std::ofstream mplFile;
664 mplFile.open(outClassFile, std::ios::trunc);
665 std::streambuf *backup = LogInfo::MapleLogger().rdbuf();
666 LogInfo::MapleLogger().rdbuf(mplFile.rdbuf());
667 /* dump class type */
668 LogInfo::MapleLogger() << "type $" << name << " ";
669 if (type->GetNameStrIdx() == it.first && type->GetKind() != kTypeByName) {
670 type->Dump(1, true);
671 } else {
672 type->Dump(1);
673 }
674 LogInfo::MapleLogger() << '\n';
675 /* restore cout */
676 LogInfo::MapleLogger().rdbuf(backup);
677 mplFile.close();
678 ;
679 }
680 }
681
FindEntryFunction()682 MIRFunction *MIRModule::FindEntryFunction()
683 {
684 for (MIRFunction *currFunc : functionList) {
685 if (currFunc->GetName() == entryFuncName) {
686 entryFunc = currFunc;
687 return currFunc;
688 }
689 }
690 return nullptr;
691 }
692
693 // given the phase name (including '.' at beginning), output the program in the
694 // module to the file with given file suffix, and file stem from
695 // this->fileName appended with phaseName
OutputAsciiMpl(const char * phaseName,const char * suffix,const std::unordered_set<std::string> * dumpFuncSet,bool emitStructureType,bool binaryform)696 void MIRModule::OutputAsciiMpl(const char *phaseName, const char *suffix,
697 const std::unordered_set<std::string> *dumpFuncSet, bool emitStructureType,
698 bool binaryform)
699 {
700 DEBUG_ASSERT(!(emitStructureType && binaryform), "Cannot emit type info in .bpl");
701 std::string fileStem;
702 std::string::size_type lastDot = fileName.find_last_of('.');
703 if (lastDot == std::string::npos) {
704 fileStem = fileName.append(phaseName);
705 } else {
706 fileStem = fileName.substr(0, lastDot).append(phaseName);
707 }
708 std::string outfileName;
709 outfileName = fileStem + suffix;
710 if (!binaryform) {
711 std::ofstream mplFile;
712 mplFile.open(outfileName, std::ios::trunc);
713 std::streambuf *backup = LogInfo::MapleLogger().rdbuf();
714 LogInfo::MapleLogger().rdbuf(mplFile.rdbuf()); // change LogInfo::MapleLogger()'s buffer to that of file
715 Dump(emitStructureType, dumpFuncSet);
716 LogInfo::MapleLogger().rdbuf(backup); // restore LogInfo::MapleLogger()'s buffer
717 mplFile.close();
718 } else {
719 BinaryMplt binaryMplt(*this);
720 binaryMplt.GetBinExport().not2mplt = true;
721 binaryMplt.Export(outfileName);
722 }
723 std::ofstream mplFile;
724 mplFile.open(outfileName, std::ios::trunc);
725 std::streambuf *backup = LogInfo::MapleLogger().rdbuf();
726 LogInfo::MapleLogger().rdbuf(mplFile.rdbuf()); // change cout's buffer to that of file
727 Dump(emitStructureType);
728 if (withDbgInfo) {
729 dbgInfo->Dump(0);
730 }
731 LogInfo::MapleLogger().rdbuf(backup); // restore cout's buffer
732 mplFile.close();
733 }
734
GetFileinfo(GStrIdx strIdx) const735 uint32 MIRModule::GetFileinfo(GStrIdx strIdx) const
736 {
737 for (auto &infoElem : fileInfo) {
738 if (infoElem.first == strIdx) {
739 return infoElem.second;
740 }
741 }
742 DEBUG_ASSERT(false, "should not be here");
743 return 0;
744 }
745
GetFileNameAsPostfix() const746 std::string MIRModule::GetFileNameAsPostfix() const
747 {
748 std::string fileNameStr = namemangler::kFileNameSplitterStr;
749 if (!fileInfo.empty()) {
750 // option 1: file name in INFO
751 uint32 fileNameIdx = GetFileinfo(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("INFO_filename"));
752 fileNameStr += GlobalTables::GetStrTable().GetStringFromStrIdx(GStrIdx(fileNameIdx));
753 } else {
754 // option 2: src file name removing ext name.
755 if (GetSrcFileInfo().size() != 0) {
756 GStrIdx idx = GetSrcFileInfo()[0].first;
757 const std::string kStr = GlobalTables::GetStrTable().GetStringFromStrIdx(idx);
758 DEBUG_ASSERT(kStr.find_last_of('.') != kStr.npos, "not found .");
759 fileNameStr += kStr.substr(0, kStr.find_last_of('.'));
760 } else {
761 DEBUG_ASSERT(0, "No fileinfo and no srcfileinfo in mpl file");
762 }
763 }
764 for (char &c : fileNameStr) {
765 if (!isalpha(c) && !isdigit(c) && c != '_' && c != '$') {
766 c = '_';
767 }
768 }
769 return fileNameStr;
770 }
771
AddClass(TyIdx tyIdx)772 void MIRModule::AddClass(TyIdx tyIdx)
773 {
774 (void)classList.insert(tyIdx);
775 }
776
RemoveClass(TyIdx tyIdx)777 void MIRModule::RemoveClass(TyIdx tyIdx)
778 {
779 (void)classList.erase(tyIdx);
780 }
781
782 #endif // MIR_FEATURE_FULL
ReleaseCurFuncMemPoolTmp()783 void MIRModule::ReleaseCurFuncMemPoolTmp()
784 {
785 CurFunction()->ReleaseMemory();
786 }
787
SetFuncInfoPrinted() const788 void MIRModule::SetFuncInfoPrinted() const
789 {
790 CurFunction()->SetInfoPrinted();
791 }
792
InitPartO2List(const std::string & list)793 void MIRModule::InitPartO2List(const std::string &list)
794 {
795 if (list.empty()) {
796 return;
797 }
798 SetHasPartO2List(true);
799 std::ifstream infile(list);
800 if (!infile.is_open()) {
801 LogInfo::MapleLogger(kLlErr) << "Cannot open partO2 function list file " << list << '\n';
802 return;
803 }
804 std::string str;
805
806 while (getline(infile, str)) {
807 if (str.empty()) {
808 continue;
809 }
810 GStrIdx funcStrIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(str);
811 partO2FuncList.insert(funcStrIdx);
812 }
813 infile.close();
814 }
815
HasNotWarned(uint32 position,uint32 stmtOriginalID)816 bool MIRModule::HasNotWarned(uint32 position, uint32 stmtOriginalID)
817 {
818 auto warnedOp = safetyWarningMap.find(position);
819 if (warnedOp == safetyWarningMap.end()) {
820 MapleSet<uint32> opSet(memPoolAllocator.Adapter());
821 opSet.emplace(stmtOriginalID);
822 safetyWarningMap.emplace(std::pair<uint32, MapleSet<uint32>>(position, std::move(opSet)));
823 return true;
824 }
825 if (warnedOp->second.find(stmtOriginalID) == warnedOp->second.end()) {
826 warnedOp->second.emplace(stmtOriginalID);
827 return true;
828 }
829 return false;
830 }
831 } // namespace maple
832