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