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