• 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 "cg_phasemanager.h"
17 #include "label_creation.h"
18 #include "offset_adjust.h"
19 #include "reg_alloc.h"
20 #if TARGAARCH64
21 #include "aarch64_emitter.h"
22 #include "aarch64_obj_emitter.h"
23 #include "aarch64_cg.h"
24 #endif
25 #if defined(TARGRISCV64)
26 #include "riscv64_emitter.h"
27 #endif
28 #if defined(TARGX86_64)
29 #include "x64_cg.h"
30 #include "x64_emitter.h"
31 #include "string_utils.h"
32 #endif
33 
34 namespace maplebe {
35 #define CLANG (module.GetSrcLang() == kSrcLangC)
36 
37 #define RELEASE(pointer)            \
38     do {                            \
39         if ((pointer) != nullptr) { \
40             delete (pointer);       \
41             (pointer) = nullptr;    \
42         }                           \
43     } while (0)
44 
45 namespace {
46 
47 #ifdef ARK_LITECG_DEBUG
DumpMIRFunc(MIRFunction & func,const char * msg,bool printAlways=false,const char * extraMsg=nullptr)48 void DumpMIRFunc(MIRFunction &func, const char *msg, bool printAlways = false, const char *extraMsg = nullptr)
49 {
50     bool dumpAll = (CGOptions::GetDumpPhases().find("*") != CGOptions::GetDumpPhases().end());
51     bool dumpFunc = CGOptions::FuncFilter(func.GetName());
52 
53     if (printAlways || (dumpAll && dumpFunc)) {
54         LogInfo::MapleLogger() << msg << '\n';
55         func.Dump();
56 
57         if (extraMsg) {
58             LogInfo::MapleLogger() << extraMsg << '\n';
59         }
60     }
61 }
62 #endif
63 
64 } /* anonymous namespace */
65 
GenerateOutPutFile(MIRModule & m)66 void CgFuncPM::GenerateOutPutFile(MIRModule &m)
67 {
68     CHECK_FATAL(cg != nullptr, "cg is null");
69     CHECK_FATAL(Triple::GetTriple().GetArch() != Triple::ArchType::UnknownArch, "should have triple init before!");
70     auto codegen = cg;
71     if (Triple::GetTriple().GetArch() == Triple::ArchType::x64) {
72         cg->Emit([codegen, &m](Emitter *emitter) {
73             assembler::Assembler &objAssm = static_cast<X64Emitter &>(*emitter).GetAssembler();
74             if (!codegen->GetCGOptions().SuppressFileInfo()) {
75                 objAssm.InitialFileInfo(m.GetInputFileName());
76             }
77         });
78     } else if (Triple::GetTriple().GetArch() == Triple::ArchType::aarch64) {
79         cg->template Emit<CG::EmitterType::AsmEmitter>([codegen, &m](Emitter *emitter) {
80             if (!codegen->GetCGOptions().SuppressFileInfo()) {
81                 emitter->EmitFileInfo(m.GetInputFileName());
82             }
83         });
84     } else {
85         CHECK_FATAL(false, "unsupportted target!");
86     }
87 }
88 
FuncLevelRun(CGFunc & cgFunc,AnalysisDataManager & serialADM)89 bool CgFuncPM::FuncLevelRun(CGFunc &cgFunc, AnalysisDataManager &serialADM)
90 {
91     bool changed = false;
92     for (size_t i = 0; i < phasesSequence.size(); ++i) {
93         SolveSkipFrom(CGOptions::GetSkipFromPhase(), i);
94         const MaplePhaseInfo *curPhase = MaplePhaseRegister::GetMaplePhaseRegister()->GetPhaseByID(phasesSequence[i]);
95         if (curPhase->IsAnalysis()) {
96             changed |= RunAnalysisPhase<MapleFunctionPhase<CGFunc>, CGFunc>(*curPhase, serialADM, cgFunc);
97         } else {
98             changed |= RunTransformPhase<MapleFunctionPhase<CGFunc>, CGFunc>(*curPhase, serialADM, cgFunc);
99             DumpFuncCGIR(cgFunc, curPhase->PhaseName());
100         }
101         SolveSkipAfter(CGOptions::GetSkipAfterPhase(), i);
102     }
103     return changed;
104 }
105 
PostOutPut(MIRModule & m)106 void CgFuncPM::PostOutPut(MIRModule &m)
107 {
108     if (Triple::GetTriple().GetArch() == Triple::ArchType::x64) {
109         cg->Emit([this](Emitter * emitter) {
110             X64Emitter *x64Emitter = static_cast<X64Emitter *>(emitter);
111             assembler::Assembler &assm = x64Emitter->GetAssembler();
112             x64Emitter->EmitGlobalVariable(*cg);
113             assm.FinalizeFileInfo();
114             assm.CloseOutput();
115         });
116     } else if (Triple::GetTriple().GetArch() == Triple::ArchType::aarch64) {
117         cg->template Emit<CG::EmitterType::AsmEmitter>([this, &m](Emitter* emitter) {
118             emitter->EmitHugeSoRoutines(true);
119             /* Emit global info */
120             EmitGlobalInfo(m);
121         });
122         cg->template Emit<CG::EmitterType::ObjEmiter>([](Emitter* emitter) {
123             emitter->Finish();
124             emitter->CloseOutput();
125         });
126     } else {
127         CHECK_FATAL(false, "unsupported target");
128     }
129 }
130 
131 /* =================== new phase manager ===================  */
132 #ifdef RA_PERF_ANALYSIS
133 extern void printLSRATime();
134 extern void printRATime();
135 #endif
136 
PhaseRun(MIRModule & m)137 bool CgFuncPM::PhaseRun(MIRModule &m)
138 {
139     // registry target based on build, cgfunc, emitter need to be registried.
140     InitializeAllTargetInfos(m.GetMemPool());
141     std::string compileTarget = "";
142     if (Triple::GetTriple().IsAarch64BeOrLe()) {
143         compileTarget = "aarch64";
144     } else if (Triple::GetTriple().GetArch() == Triple::ArchType::x64) {
145         compileTarget = "x86";
146     } else {
147         CHECK_FATAL(false, "unsupport");
148     }
149     const Target *TheTarget = nullptr;
150     TheTarget = TargetRegistry::lookupTarget(compileTarget);
151     // get target based on option
152     CreateCGAndBeCommon(m, TheTarget);
153     bool changed = false;
154     if (cgOptions->IsRunCG()) {
155         GenerateOutPutFile(m);
156 
157         /* Run the cg optimizations phases */
158         PrepareLower(m);
159 
160         uint32 countFuncId = 0;
161         unsigned long rangeNum = 0;
162 
163         auto userDefinedOptLevel = cgOptions->GetOptimizeLevel();
164         cg->EnrollTargetPhases(this);
165 
166         auto admMempool = AllocateMemPoolInPhaseManager("cg phase manager's analysis data manager mempool");
167         auto *serialADM = GetManagerMemPool()->New<AnalysisDataManager>(*(admMempool.get()));
168         for (auto it = m.GetFunctionList().begin(); it != m.GetFunctionList().end(); ++it) {
169             DEBUG_ASSERT(serialADM->CheckAnalysisInfoEmpty(), "clean adm before function run");
170             MIRFunction *mirFunc = *it;
171             if (mirFunc->GetBody() == nullptr) {
172                 continue;
173             }
174             if (userDefinedOptLevel == CGOptions::kLevel2 && m.HasPartO2List()) {
175 #ifdef ARK_LITECG_DEBUG
176                 if (m.IsInPartO2List(mirFunc->GetNameStrIdx())) {
177                     cgOptions->EnableO2();
178                 } else {
179                     cgOptions->EnableO0();
180                 }
181 #endif
182                 ClearAllPhases();
183                 cg->EnrollTargetPhases(this);
184                 cg->UpdateCGOptions(*cgOptions);
185                 Globals::GetInstance()->SetOptimLevel(cgOptions->GetOptimizeLevel());
186             }
187             /* LowerIR. */
188             m.SetCurFunction(mirFunc);
189 
190             if (m.GetFlavor() != MIRFlavor::kFlavorLmbc) {
191                 DoFuncCGLower(m, *mirFunc);
192             }
193             /* create CGFunc */
194             MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStidx(mirFunc->GetStIdx().Idx());
195             CHECK_NULL_FATAL(funcSt);
196             auto funcMp = std::make_unique<ThreadLocalMemPool>(memPoolCtrler, funcSt->GetName());
197             auto stackMp = std::make_unique<StackMemPool>(funcMp->GetCtrler(), "");
198             MapleAllocator funcScopeAllocator(funcMp.get());
199             mirFunc->SetPuidxOrigin(++countFuncId);
200             CGFunc *cgFunc =
201                 cg->CreateCGFunc(m, *mirFunc, *beCommon, *funcMp, *stackMp, funcScopeAllocator, countFuncId);
202             CHECK_FATAL(cgFunc != nullptr, "Create CG Function failed in cg_phase_manager");
203             CG::SetCurCGFunc(*cgFunc);
204 
205             /* Run the cg optimizations phases. */
206             if (CGOptions::UseRange() && rangeNum >= CGOptions::GetRangeBegin() &&
207                 rangeNum <= CGOptions::GetRangeEnd()) {
208                 CGOptions::EnableInRange();
209             }
210             changed = FuncLevelRun(*cgFunc, *serialADM);
211             /* Delete mempool. */
212             mirFunc->ReleaseCodeMemory();
213             ++rangeNum;
214             CGOptions::DisableInRange();
215         }
216         PostOutPut(m);
217 #ifdef RA_PERF_ANALYSIS
218         if (cgOptions->IsEnableTimePhases()) {
219             printLSRATime();
220             printRATime();
221         }
222 #endif
223     } else {
224         LogInfo::MapleLogger(kLlErr) << "Skipped generating .s because -no-cg is given" << '\n';
225     }
226     RELEASE(cg);
227     RELEASE(beCommon);
228     return changed;
229 }
230 
DumpFuncCGIR(const CGFunc & f,const std::string & phaseName) const231 void CgFuncPM::DumpFuncCGIR(const CGFunc &f, const std::string &phaseName) const
232 {
233 #ifdef ARK_LITECG_DEBUG
234     if (CGOptions::DumpPhase(phaseName) && CGOptions::FuncFilter(f.GetName())) {
235         LogInfo::MapleLogger() << "\n******** CG IR After " << phaseName << ": *********\n";
236         f.DumpCGIR();
237     }
238 #endif
239 }
240 
EmitGlobalInfo(MIRModule & m) const241 void CgFuncPM::EmitGlobalInfo(MIRModule &m) const
242 {
243     EmitDuplicatedAsmFunc(m);
244     cg->template Emit<CG::EmitterType::AsmEmitter>([](Emitter* emitter) {
245         emitter->EmitGlobalVariable();
246         emitter->CloseOutput();
247         emitter->WriteDebugCommentToFile();
248     });
249 }
250 
CreateCGAndBeCommon(MIRModule & m,const Target * t)251 void CgFuncPM::CreateCGAndBeCommon(MIRModule &m, const Target *t)
252 {
253     DEBUG_ASSERT(cgOptions != nullptr, "New cg phase manager running FAILED  :: cgOptions unset");
254     auto outputFileName = m.GetOutputFileName();
255     Emitter *objEmitter = nullptr;
256     Emitter *asmEmitter = nullptr;
257     cg = t->createCG(m, *cgOptions, cgOptions->GetEHExclusiveFunctionNameVec(), CGOptions::GetCyclePatternMap());
258     CHECK_FATAL(cg, "you may not register the target");
259     if (Triple::GetTriple().GetArch() == Triple::ArchType::x64) {
260         assembler::Assembler *asmAssembler = nullptr;
261         if (cg->GetCGOptions().IsAsmEmitterEnable()) {
262             asmAssembler = new assembler::AsmAssembler(outputFileName);
263             asmEmitter = t->createDecoupledEmitter(*cg, *asmAssembler);
264         }
265         outputFileName = outputFileName.replace(outputFileName.length() - 1, 1, 1, 'o');
266         auto objAssembler = new assembler::ElfAssembler(outputFileName);
267         objEmitter = t->createDecoupledEmitter(*cg, *objAssembler);
268     } else if (Triple::GetTriple().GetArch() == Triple::ArchType::aarch64) {
269         if (cgOptions->IsAsmEmitterEnable()) {
270             asmEmitter = m.GetMemPool()->New<AArch64AsmEmitter>(*cg, outputFileName);
271         }
272         outputFileName = outputFileName.replace(outputFileName.length() - 1, 1, 1, 'o');
273         objEmitter = m.GetMemPool()->New<AArch64ObjEmitter>(*cg, outputFileName);
274     } else {
275         CHECK_FATAL(false, "unsupportted");
276     }
277     CHECK_FATAL(objEmitter, "you may not register emitter");
278     cg->SetObjEmitter(*objEmitter);
279     if (cg->GetCGOptions().IsAsmEmitterEnable()) {
280         CHECK_FATAL(asmEmitter, "you may not register emitter");
281         cg->SetAsmEmitter(*asmEmitter);
282     }
283 #ifdef ARK_LITECG_DEBUG
284     TargetMachine *targetMachine = t->createTargetMachine();
285     CHECK_FATAL(targetMachine, "you may not register targetMachine");
286     cg->SetTargetMachine(*targetMachine);
287 #endif
288 
289     /* We initialize a couple of BECommon's tables using the size information of GlobalTables.type_table_.
290      * So, BECommon must be allocated after all the parsing is done and user-defined types are all acounted.
291      */
292     beCommon = new BECommon(m);
293     Globals::GetInstance()->SetBECommon(*beCommon);
294     Globals::GetInstance()->SetTarget(*cg);
295 
296     if (Triple::GetTriple().IsAarch64BeOrLe()) {
297         CGOptions::EnableFramePointer();
298     }
299 }
300 
PrepareLower(MIRModule & m)301 void CgFuncPM::PrepareLower(MIRModule &m)
302 {
303     mirLower = GetManagerMemPool()->New<MIRLower>(m, nullptr);
304     mirLower->Init();
305     cgLower =
306         GetManagerMemPool()->New<CGLowerer>(m, *beCommon, cg->GenerateExceptionHandlingCode(), cg->GenerateVerboseCG());
307     cgLower->SetCheckLoadStore(false);
308 }
309 
DoFuncCGLower(const MIRModule & m,MIRFunction & mirFunc)310 void CgFuncPM::DoFuncCGLower(const MIRModule &m, MIRFunction &mirFunc)
311 {
312     if (m.GetFlavor() <= kFeProduced) {
313         mirLower->SetLowerCG();
314         mirLower->SetMirFunc(&mirFunc);
315 #ifdef ARK_LITECG_DEBUG
316         DumpMIRFunc(mirFunc, "************* before MIRLowerer **************");
317 #endif
318         mirLower->LowerFunc(mirFunc);
319     }
320 
321 #ifdef ARK_LITECG_DEBUG
322     bool isNotQuiet = false;
323     DumpMIRFunc(mirFunc, "************* before CGLowerer **************", isNotQuiet);
324 #endif
325 
326     cgLower->LowerFunc(mirFunc);
327 
328 #ifdef ARK_LITECG_DEBUG
329     DumpMIRFunc(mirFunc, "************* after  CGLowerer **************", isNotQuiet,
330                 "************* end    CGLowerer **************");
331 #endif
332 }
333 
EmitDuplicatedAsmFunc(MIRModule & m) const334 void CgFuncPM::EmitDuplicatedAsmFunc(MIRModule &m) const
335 {
336 #ifdef ARK_LITECG_DEBUG
337     if (CGOptions::IsDuplicateAsmFileEmpty()) {
338         return;
339     }
340 
341     std::ifstream duplicateAsmFileFD(CGOptions::GetDuplicateAsmFile());
342 
343     if (!duplicateAsmFileFD.is_open()) {
344         duplicateAsmFileFD.close();
345         ERR(kLncErr, " %s open failed!", CGOptions::GetDuplicateAsmFile().c_str());
346         return;
347     }
348     std::string contend;
349     bool onlyForFramework = false;
350     bool isFramework = IsFramework(m);
351 
352     while (getline(duplicateAsmFileFD, contend)) {
353         if (!contend.compare("#Libframework_start")) {
354             onlyForFramework = true;
355         }
356 
357         if (!contend.compare("#Libframework_end")) {
358             onlyForFramework = false;
359         }
360 
361         if (onlyForFramework && !isFramework) {
362             continue;
363         }
364 
365         cg->Emit([&contend](Emitter *emitter) {
366             emitter->Emit(contend + "\n");
367         });
368     }
369     duplicateAsmFileFD.close();
370 #endif
371 }
372 
IsFramework(MIRModule & m) const373 bool CgFuncPM::IsFramework([[maybe_unused]] MIRModule &m) const
374 {
375     return false;
376 }
377 MAPLE_TRANSFORM_PHASE_REGISTER(CgFuncPM, cgFuncPhaseManager)
378 /* register codegen common phases */
379 MAPLE_TRANSFORM_PHASE_REGISTER(CgLayoutFrame, layoutstackframe)
380 MAPLE_TRANSFORM_PHASE_REGISTER(CgCreateLabel, createstartendlabel)
381 MAPLE_TRANSFORM_PHASE_REGISTER(InstructionSelector, instructionselector)
382 MAPLE_TRANSFORM_PHASE_REGISTER(CgMoveRegArgs, moveargs)
383 MAPLE_TRANSFORM_PHASE_REGISTER(CgRegAlloc, regalloc)
384 MAPLE_TRANSFORM_PHASE_REGISTER(CgFrameFinalize, framefinalize)
385 MAPLE_TRANSFORM_PHASE_REGISTER(CgGenProEpiLog, generateproepilog)
386 } /* namespace maplebe */
387