• 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 ===================  */
PhaseRun(MIRModule & m)132 bool CgFuncPM::PhaseRun(MIRModule &m)
133 {
134     // registry target based on build, cgfunc, emitter need to be registried.
135     InitializeAllTargetInfos(m.GetMemPool());
136     std::string compileTarget = "";
137     if (Triple::GetTriple().IsAarch64BeOrLe()) {
138         compileTarget = "aarch64";
139     } else if (Triple::GetTriple().GetArch() == Triple::ArchType::x64) {
140         compileTarget = "x86";
141     } else {
142         CHECK_FATAL(false, "unsupport");
143     }
144     const Target *TheTarget = nullptr;
145     TheTarget = TargetRegistry::lookupTarget(compileTarget);
146     // get target based on option
147     CreateCGAndBeCommon(m, TheTarget);
148     bool changed = false;
149     if (cgOptions->IsRunCG()) {
150         GenerateOutPutFile(m);
151 
152         /* Run the cg optimizations phases */
153         PrepareLower(m);
154 
155         uint32 countFuncId = 0;
156         unsigned long rangeNum = 0;
157 
158         auto userDefinedOptLevel = cgOptions->GetOptimizeLevel();
159         cg->EnrollTargetPhases(this);
160 
161         auto admMempool = AllocateMemPoolInPhaseManager("cg phase manager's analysis data manager mempool");
162         auto *serialADM = GetManagerMemPool()->New<AnalysisDataManager>(*(admMempool.get()));
163         for (auto it = m.GetFunctionList().begin(); it != m.GetFunctionList().end(); ++it) {
164             DEBUG_ASSERT(serialADM->CheckAnalysisInfoEmpty(), "clean adm before function run");
165             MIRFunction *mirFunc = *it;
166             if (mirFunc->GetBody() == nullptr) {
167                 continue;
168             }
169             if (userDefinedOptLevel == CGOptions::kLevel2 && m.HasPartO2List()) {
170 #ifdef ARK_LITECG_DEBUG
171                 if (m.IsInPartO2List(mirFunc->GetNameStrIdx())) {
172                     cgOptions->EnableO2();
173                 } else {
174                     cgOptions->EnableO0();
175                 }
176 #endif
177                 ClearAllPhases();
178                 cg->EnrollTargetPhases(this);
179                 cg->UpdateCGOptions(*cgOptions);
180                 Globals::GetInstance()->SetOptimLevel(cgOptions->GetOptimizeLevel());
181             }
182             /* LowerIR. */
183             m.SetCurFunction(mirFunc);
184 
185             if (m.GetFlavor() != MIRFlavor::kFlavorLmbc) {
186                 DoFuncCGLower(m, *mirFunc);
187             }
188             /* create CGFunc */
189             MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStidx(mirFunc->GetStIdx().Idx());
190             CHECK_NULL_FATAL(funcSt);
191             auto funcMp = std::make_unique<ThreadLocalMemPool>(memPoolCtrler, funcSt->GetName());
192             auto stackMp = std::make_unique<StackMemPool>(funcMp->GetCtrler(), "");
193             MapleAllocator funcScopeAllocator(funcMp.get());
194             mirFunc->SetPuidxOrigin(++countFuncId);
195             CGFunc *cgFunc =
196                 cg->CreateCGFunc(m, *mirFunc, *beCommon, *funcMp, *stackMp, funcScopeAllocator, countFuncId);
197             CHECK_FATAL(cgFunc != nullptr, "Create CG Function failed in cg_phase_manager");
198             CG::SetCurCGFunc(*cgFunc);
199 
200             /* Run the cg optimizations phases. */
201             if (CGOptions::UseRange() && rangeNum >= CGOptions::GetRangeBegin() &&
202                 rangeNum <= CGOptions::GetRangeEnd()) {
203                 CGOptions::EnableInRange();
204             }
205             changed = FuncLevelRun(*cgFunc, *serialADM);
206             /* Delete mempool. */
207             mirFunc->ReleaseCodeMemory();
208             ++rangeNum;
209             CGOptions::DisableInRange();
210         }
211         PostOutPut(m);
212 #ifdef RA_PERF_ANALYSIS
213         if (cgOptions->IsEnableTimePhases()) {
214             printLSRATime();
215         }
216 #endif
217     } else {
218         LogInfo::MapleLogger(kLlErr) << "Skipped generating .s because -no-cg is given" << '\n';
219     }
220     RELEASE(cg);
221     RELEASE(beCommon);
222     return changed;
223 }
224 
DumpFuncCGIR(const CGFunc & f,const std::string & phaseName) const225 void CgFuncPM::DumpFuncCGIR(const CGFunc &f, const std::string &phaseName) const
226 {
227 #ifdef ARK_LITECG_DEBUG
228     if (CGOptions::DumpPhase(phaseName) && CGOptions::FuncFilter(f.GetName())) {
229         LogInfo::MapleLogger() << "\n******** CG IR After " << phaseName << ": *********\n";
230         f.DumpCGIR();
231     }
232 #endif
233 }
234 
EmitGlobalInfo(MIRModule & m) const235 void CgFuncPM::EmitGlobalInfo(MIRModule &m) const
236 {
237     EmitDuplicatedAsmFunc(m);
238     cg->template Emit<CG::EmitterType::AsmEmitter>([](Emitter* emitter) {
239         emitter->EmitGlobalVariable();
240         emitter->CloseOutput();
241         emitter->WriteDebugCommentToFile();
242     });
243 }
244 
CreateCGAndBeCommon(MIRModule & m,const Target * t)245 void CgFuncPM::CreateCGAndBeCommon(MIRModule &m, const Target *t)
246 {
247     DEBUG_ASSERT(cgOptions != nullptr, "New cg phase manager running FAILED  :: cgOptions unset");
248     auto outputFileName = m.GetOutputFileName();
249     Emitter *objEmitter = nullptr;
250     Emitter *asmEmitter = nullptr;
251     cg = t->createCG(m, *cgOptions, cgOptions->GetEHExclusiveFunctionNameVec(), CGOptions::GetCyclePatternMap());
252     CHECK_FATAL(cg, "you may not register the target");
253     if (Triple::GetTriple().GetArch() == Triple::ArchType::x64) {
254         assembler::Assembler *asmAssembler = nullptr;
255         if (cg->GetCGOptions().IsAsmEmitterEnable()) {
256             asmAssembler = new assembler::AsmAssembler(outputFileName);
257             asmEmitter = t->createDecoupledEmitter(*cg, *asmAssembler);
258         }
259         outputFileName = outputFileName.replace(outputFileName.length() - 1, 1, 1, 'o');
260         auto objAssembler = new assembler::ElfAssembler(outputFileName);
261         objEmitter = t->createDecoupledEmitter(*cg, *objAssembler);
262     } else if (Triple::GetTriple().GetArch() == Triple::ArchType::aarch64) {
263         if (cgOptions->IsAsmEmitterEnable()) {
264             asmEmitter = m.GetMemPool()->New<AArch64AsmEmitter>(*cg, outputFileName);
265         }
266         outputFileName = outputFileName.replace(outputFileName.length() - 1, 1, 1, 'o');
267         objEmitter = m.GetMemPool()->New<AArch64ObjEmitter>(*cg, outputFileName);
268     } else {
269         CHECK_FATAL(false, "unsupportted");
270     }
271     CHECK_FATAL(objEmitter, "you may not register emitter");
272     cg->SetObjEmitter(*objEmitter);
273     if (cg->GetCGOptions().IsAsmEmitterEnable()) {
274         CHECK_FATAL(asmEmitter, "you may not register emitter");
275         cg->SetAsmEmitter(*asmEmitter);
276     }
277 #ifdef ARK_LITECG_DEBUG
278     TargetMachine *targetMachine = t->createTargetMachine();
279     CHECK_FATAL(targetMachine, "you may not register targetMachine");
280     cg->SetTargetMachine(*targetMachine);
281 #endif
282 
283     /* We initialize a couple of BECommon's tables using the size information of GlobalTables.type_table_.
284      * So, BECommon must be allocated after all the parsing is done and user-defined types are all acounted.
285      */
286     beCommon = new BECommon(m);
287     Globals::GetInstance()->SetBECommon(*beCommon);
288     Globals::GetInstance()->SetTarget(*cg);
289 
290     if (Triple::GetTriple().IsAarch64BeOrLe()) {
291         CGOptions::EnableFramePointer();
292     }
293 }
294 
PrepareLower(MIRModule & m)295 void CgFuncPM::PrepareLower(MIRModule &m)
296 {
297     mirLower = GetManagerMemPool()->New<MIRLower>(m, nullptr);
298     mirLower->Init();
299     cgLower =
300         GetManagerMemPool()->New<CGLowerer>(m, *beCommon, cg->GenerateExceptionHandlingCode(), cg->GenerateVerboseCG());
301     cgLower->SetCheckLoadStore(false);
302 }
303 
DoFuncCGLower(const MIRModule & m,MIRFunction & mirFunc)304 void CgFuncPM::DoFuncCGLower(const MIRModule &m, MIRFunction &mirFunc)
305 {
306     if (m.GetFlavor() <= kFeProduced) {
307         mirLower->SetLowerCG();
308         mirLower->SetMirFunc(&mirFunc);
309 #ifdef ARK_LITECG_DEBUG
310         DumpMIRFunc(mirFunc, "************* before MIRLowerer **************");
311 #endif
312         mirLower->LowerFunc(mirFunc);
313     }
314 
315 #ifdef ARK_LITECG_DEBUG
316     bool isNotQuiet = false;
317     DumpMIRFunc(mirFunc, "************* before CGLowerer **************", isNotQuiet);
318 #endif
319 
320     cgLower->LowerFunc(mirFunc);
321 
322 #ifdef ARK_LITECG_DEBUG
323     DumpMIRFunc(mirFunc, "************* after  CGLowerer **************", isNotQuiet,
324                 "************* end    CGLowerer **************");
325 #endif
326 }
327 
EmitDuplicatedAsmFunc(MIRModule & m) const328 void CgFuncPM::EmitDuplicatedAsmFunc(MIRModule &m) const
329 {
330 #ifdef ARK_LITECG_DEBUG
331     if (CGOptions::IsDuplicateAsmFileEmpty()) {
332         return;
333     }
334 
335     std::ifstream duplicateAsmFileFD(CGOptions::GetDuplicateAsmFile());
336 
337     if (!duplicateAsmFileFD.is_open()) {
338         duplicateAsmFileFD.close();
339         ERR(kLncErr, " %s open failed!", CGOptions::GetDuplicateAsmFile().c_str());
340         return;
341     }
342     std::string contend;
343     bool onlyForFramework = false;
344     bool isFramework = IsFramework(m);
345 
346     while (getline(duplicateAsmFileFD, contend)) {
347         if (!contend.compare("#Libframework_start")) {
348             onlyForFramework = true;
349         }
350 
351         if (!contend.compare("#Libframework_end")) {
352             onlyForFramework = false;
353         }
354 
355         if (onlyForFramework && !isFramework) {
356             continue;
357         }
358 
359         cg->Emit([&contend](Emitter *emitter) {
360             emitter->Emit(contend + "\n");
361         });
362     }
363     duplicateAsmFileFD.close();
364 #endif
365 }
366 
IsFramework(MIRModule & m) const367 bool CgFuncPM::IsFramework([[maybe_unused]] MIRModule &m) const
368 {
369     return false;
370 }
371 MAPLE_TRANSFORM_PHASE_REGISTER(CgFuncPM, cgFuncPhaseManager)
372 /* register codegen common phases */
373 MAPLE_TRANSFORM_PHASE_REGISTER(CgLayoutFrame, layoutstackframe)
374 MAPLE_TRANSFORM_PHASE_REGISTER(CgCreateLabel, createstartendlabel)
375 MAPLE_TRANSFORM_PHASE_REGISTER(InstructionSelector, instructionselector)
376 MAPLE_TRANSFORM_PHASE_REGISTER(CgMoveRegArgs, moveargs)
377 MAPLE_TRANSFORM_PHASE_REGISTER(CgRegAlloc, regalloc)
378 MAPLE_TRANSFORM_PHASE_REGISTER(CgFrameFinalize, framefinalize)
379 MAPLE_TRANSFORM_PHASE_REGISTER(CgGenProEpiLog, generateproepilog)
380 } /* namespace maplebe */
381