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 "aarch64_emitter.h"
17 #include <sys/stat.h>
18 #include "aarch64_cgfunc.h"
19 #include "aarch64_cg.h"
20 #include "metadata_layout.h"
21 #include "cfi.h"
22 #include "dbg.h"
23 #include "aarch64_obj_emitter.h"
24
25 namespace {
26 using namespace maple;
27 // map func name to <filename, insnCount> pair
28 using Func2CodeInsnMap = std::unordered_map<std::string, std::pair<std::string, uint32>>;
29 Func2CodeInsnMap func2CodeInsnMap {
30 {"Ljava_2Flang_2FString_3B_7ChashCode_7C_28_29I", {"maple/mrt/codetricks/arch/arm64/hashCode.s", 29}},
31 {"Ljava_2Flang_2FString_3B_7Cequals_7C_28Ljava_2Flang_2FObject_3B_29Z",
32 {"maple/mrt/codetricks/arch/arm64/stringEquals.s", 50}}};
33 constexpr uint32 kQuadInsnCount = 2;
34
GetMethodLabel(const std::string & methodName,std::string & methodLabel)35 void GetMethodLabel(const std::string &methodName, std::string &methodLabel)
36 {
37 methodLabel = ".Lmethod_desc." + methodName;
38 }
39 } // namespace
40
41 namespace maplebe {
42 using namespace maple;
43
EmitRefToMethodDesc(FuncEmitInfo & funcEmitInfo,Emitter & emitter)44 void AArch64AsmEmitter::EmitRefToMethodDesc(FuncEmitInfo &funcEmitInfo, Emitter &emitter)
45 {
46 CGFunc &cgFunc = funcEmitInfo.GetCGFunc();
47 if (!cgFunc.GetFunction().IsJava()) {
48 return;
49 }
50 std::string methodDescLabel;
51 GetMethodLabel(cgFunc.GetFunction().GetName(), methodDescLabel);
52 (void)emitter.Emit("\t.word " + methodDescLabel + "-.\n");
53 emitter.IncreaseJavaInsnCount();
54 }
55
EmitRefToMethodInfo(FuncEmitInfo & funcEmitInfo,Emitter & emitter)56 void AArch64AsmEmitter::EmitRefToMethodInfo(FuncEmitInfo &funcEmitInfo, Emitter &emitter)
57 {
58 CGFunc &cgFunc = funcEmitInfo.GetCGFunc();
59 if (cgFunc.GetFunction().GetModule()->IsJavaModule()) {
60 std::string labelName = ".Label.name." + cgFunc.GetFunction().GetName();
61 (void)emitter.Emit("\t.word " + labelName + " - .\n");
62 }
63 }
64
65 /*
66 * emit java method description which contains address and size of local reference area
67 * as well as method metadata.
68 */
EmitMethodDesc(FuncEmitInfo & funcEmitInfo,Emitter & emitter)69 void AArch64AsmEmitter::EmitMethodDesc(FuncEmitInfo &funcEmitInfo, Emitter &emitter)
70 {
71 CGFunc &cgFunc = funcEmitInfo.GetCGFunc();
72 if (!cgFunc.GetFunction().IsJava()) {
73 return;
74 }
75 (void)emitter.Emit("\t.section\t.rodata\n");
76 (void)emitter.Emit("\t.align\t2\n");
77 std::string methodInfoLabel;
78 GetMethodLabel(cgFunc.GetFunction().GetName(), methodInfoLabel);
79 (void)emitter.Emit(methodInfoLabel + ":\n");
80 EmitRefToMethodInfo(funcEmitInfo, emitter);
81 /* local reference area */
82 AArch64MemLayout *memLayout = static_cast<AArch64MemLayout *>(cgFunc.GetMemlayout());
83 int32 refOffset = memLayout->GetRefLocBaseLoc();
84 uint32 refNum = memLayout->GetSizeOfRefLocals() / kOffsetAlign;
85 /* for ea usage */
86 AArch64CGFunc &aarchCGFunc = static_cast<AArch64CGFunc &>(cgFunc);
87 IntrinsiccallNode *cleanEANode = aarchCGFunc.GetCleanEANode();
88 if (cleanEANode != nullptr) {
89 refNum += static_cast<uint32>(cleanEANode->NumOpnds());
90 refOffset -= static_cast<int32>(cleanEANode->NumOpnds() * kIntregBytelen);
91 }
92 (void)emitter.Emit("\t.short ").Emit(refOffset).Emit("\n");
93 (void)emitter.Emit("\t.short ").Emit(refNum).Emit("\n");
94 }
95
96 /* the fast_exception_handling lsda */
EmitFastLSDA(FuncEmitInfo & funcEmitInfo)97 void AArch64AsmEmitter::EmitFastLSDA(FuncEmitInfo &funcEmitInfo)
98 {
99 CGFunc &cgFunc = funcEmitInfo.GetCGFunc();
100 AArch64CGFunc &aarchCGFunc = static_cast<AArch64CGFunc &>(cgFunc);
101 CG *currCG = cgFunc.GetCG();
102
103 Emitter *emitter = currCG->GetEmitter();
104 PUIdx pIdx = currCG->GetMIRModule()->CurFunction()->GetPuidx();
105 const std::string &idx = strdup(std::to_string(pIdx).c_str());
106 /*
107 * .word 0xFFFFFFFF
108 * .word .Label.LTest_3B_7C_3Cinit_3E_7C_28_29V3-func_start_label
109 */
110 (void)emitter->Emit("\t.word 0xFFFFFFFF\n");
111 (void)emitter->Emit("\t.word .L." + idx + "__");
112 if (aarchCGFunc.NeedCleanup()) {
113 emitter->Emit(cgFunc.GetCleanupLabel()->GetLabelIdx());
114 } else {
115 DEBUG_ASSERT(!cgFunc.GetExitBBsVec().empty(), "exitbbsvec is empty in AArch64AsmEmitter::EmitFastLSDA");
116 emitter->Emit(cgFunc.GetExitBB(0)->GetLabIdx());
117 }
118 emitter->Emit("-.L." + idx + "__").Emit(cgFunc.GetStartLabel()->GetLabelIdx()).Emit("\n");
119 emitter->IncreaseJavaInsnCount();
120 }
121
122 /* the normal gcc_except_table */
EmitFullLSDA(FuncEmitInfo & funcEmitInfo)123 void AArch64AsmEmitter::EmitFullLSDA(FuncEmitInfo &funcEmitInfo)
124 {
125 CGFunc &cgFunc = funcEmitInfo.GetCGFunc();
126 AArch64CGFunc &aarchCGFunc = static_cast<AArch64CGFunc &>(cgFunc);
127 CG *currCG = cgFunc.GetCG();
128 EHFunc *ehFunc = cgFunc.GetEHFunc();
129 Emitter *emitter = currCG->GetEmitter();
130 /* emit header */
131 emitter->Emit("\t.align 3\n");
132 emitter->Emit("\t.section .gcc_except_table,\"a\",@progbits\n");
133 emitter->Emit("\t.align 3\n");
134 /* emit LSDA header */
135 LSDAHeader *lsdaHeader = ehFunc->GetLSDAHeader();
136 emitter->EmitStmtLabel(lsdaHeader->GetLSDALabel()->GetLabelIdx());
137 emitter->Emit("\t.byte ").Emit(lsdaHeader->GetLPStartEncoding()).Emit("\n");
138 emitter->Emit("\t.byte ").Emit(lsdaHeader->GetTTypeEncoding()).Emit("\n");
139 emitter->Emit("\t.uleb128 ");
140 emitter->EmitLabelPair(lsdaHeader->GetTTypeOffset());
141 emitter->EmitStmtLabel(lsdaHeader->GetTTypeOffset().GetStartOffset()->GetLabelIdx());
142 /* emit call site table */
143 emitter->Emit("\t.byte ").Emit(lsdaHeader->GetCallSiteEncoding()).Emit("\n");
144 /* callsite table size */
145 emitter->Emit("\t.uleb128 ");
146 emitter->EmitLabelPair(ehFunc->GetLSDACallSiteTable()->GetCSTable());
147 /* callsite start */
148 emitter->EmitStmtLabel(ehFunc->GetLSDACallSiteTable()->GetCSTable().GetStartOffset()->GetLabelIdx());
149 ehFunc->GetLSDACallSiteTable()->SortCallSiteTable([&aarchCGFunc](const LSDACallSite *a, const LSDACallSite *b) {
150 CHECK_FATAL(a != nullptr, "nullptr check");
151 CHECK_FATAL(b != nullptr, "nullptr check");
152 LabelIDOrder id1 = aarchCGFunc.GetLabelOperand(a->csStart.GetEndOffset()->GetLabelIdx())->GetLabelOrder();
153 LabelIDOrder id2 = aarchCGFunc.GetLabelOperand(b->csStart.GetEndOffset()->GetLabelIdx())->GetLabelOrder();
154 /* id1 and id2 should not be default value -1u */
155 CHECK_FATAL(id1 != 0xFFFFFFFF, "illegal label order assigned");
156 CHECK_FATAL(id2 != 0xFFFFFFFF, "illegal label order assigned");
157 return id1 < id2;
158 });
159 const MapleVector<LSDACallSite *> &callSiteTable = ehFunc->GetLSDACallSiteTable()->GetCallSiteTable();
160 for (size_t i = 0; i < callSiteTable.size(); ++i) {
161 LSDACallSite *lsdaCallSite = callSiteTable[i];
162 emitter->Emit("\t.uleb128 ");
163 emitter->EmitLabelPair(lsdaCallSite->csStart);
164
165 emitter->Emit("\t.uleb128 ");
166 emitter->EmitLabelPair(lsdaCallSite->csLength);
167
168 if (lsdaCallSite->csLandingPad.GetStartOffset()) {
169 emitter->Emit("\t.uleb128 ");
170 emitter->EmitLabelPair(lsdaCallSite->csLandingPad);
171 } else {
172 DEBUG_ASSERT(lsdaCallSite->csAction == 0, "csAction error!");
173 emitter->Emit("\t.uleb128 ");
174 if (aarchCGFunc.NeedCleanup()) {
175 /* if landing pad is 0, we emit this call site as cleanup code */
176 LabelPair cleaupCode;
177 cleaupCode.SetStartOffset(cgFunc.GetStartLabel());
178 cleaupCode.SetEndOffset(cgFunc.GetCleanupLabel());
179 emitter->EmitLabelPair(cleaupCode);
180 } else if (cgFunc.GetFunction().IsJava()) {
181 DEBUG_ASSERT(!cgFunc.GetExitBBsVec().empty(), "exitbbsvec is empty in AArch64Emitter::EmitFullLSDA");
182 PUIdx pIdx = cgFunc.GetMirModule().CurFunction()->GetPuidx();
183 const std::string &idx = strdup(std::to_string(pIdx).c_str());
184 (void)emitter->Emit(".L." + idx).Emit("__").Emit(cgFunc.GetExitBB(0)->GetLabIdx());
185 (void)emitter->Emit(" - .L." + idx).Emit("__").Emit(cgFunc.GetStartLabel()->GetLabelIdx()).Emit("\n");
186 } else {
187 emitter->Emit("0\n");
188 }
189 }
190 emitter->Emit("\t.uleb128 ").Emit(lsdaCallSite->csAction).Emit("\n");
191 }
192
193 /*
194 * quick hack: insert a call site entry for the whole function body.
195 * this will hand in any pending (uncaught) exception to its caller. Note that
196 * __gxx_personality_v0 in libstdc++ is coded so that if exception table exists,
197 * the call site table must have an entry for any possibly raised exception,
198 * otherwise __cxa_call_terminate will be invoked immediately, thus the caller
199 * does not get the chance to take charge.
200 */
201 if (aarchCGFunc.NeedCleanup() || cgFunc.GetFunction().IsJava()) {
202 /* call site for clean-up */
203 LabelPair funcStart;
204 funcStart.SetStartOffset(cgFunc.GetStartLabel());
205 funcStart.SetEndOffset(cgFunc.GetStartLabel());
206 emitter->Emit("\t.uleb128 ");
207 emitter->EmitLabelPair(funcStart);
208 LabelPair funcLength;
209 funcLength.SetStartOffset(cgFunc.GetStartLabel());
210 funcLength.SetEndOffset(cgFunc.GetCleanupLabel());
211 emitter->Emit("\t.uleb128 ");
212 emitter->EmitLabelPair(funcLength);
213 LabelPair cleaupCode;
214 cleaupCode.SetStartOffset(cgFunc.GetStartLabel());
215 cleaupCode.SetEndOffset(cgFunc.GetCleanupLabel());
216 emitter->Emit("\t.uleb128 ");
217 if (aarchCGFunc.NeedCleanup()) {
218 emitter->EmitLabelPair(cleaupCode);
219 } else {
220 DEBUG_ASSERT(!cgFunc.GetExitBBsVec().empty(), "exitbbsvec is empty in AArch64AsmEmitter::EmitFullLSDA");
221 PUIdx pIdx = cgFunc.GetMirModule().CurFunction()->GetPuidx();
222 const std::string &idx = strdup(std::to_string(pIdx).c_str());
223 (void)emitter->Emit(".L." + idx).Emit("__").Emit(cgFunc.GetExitBB(0)->GetLabIdx());
224 (void)emitter->Emit(" - .L." + idx).Emit("__").Emit(cgFunc.GetStartLabel()->GetLabelIdx()).Emit("\n");
225 }
226 emitter->Emit("\t.uleb128 0\n");
227 if (!cgFunc.GetFunction().IsJava()) {
228 /* call site for stack unwind */
229 LabelPair unwindStart;
230 unwindStart.SetStartOffset(cgFunc.GetStartLabel());
231 unwindStart.SetEndOffset(cgFunc.GetCleanupLabel());
232 emitter->Emit("\t.uleb128 ");
233 emitter->EmitLabelPair(unwindStart);
234 LabelPair unwindLength;
235 unwindLength.SetStartOffset(cgFunc.GetCleanupLabel());
236 unwindLength.SetEndOffset(cgFunc.GetEndLabel());
237 emitter->Emit("\t.uleb128 ");
238 emitter->EmitLabelPair(unwindLength);
239 emitter->Emit("\t.uleb128 0\n");
240 emitter->Emit("\t.uleb128 0\n");
241 }
242 }
243 /* callsite end label */
244 emitter->EmitStmtLabel(ehFunc->GetLSDACallSiteTable()->GetCSTable().GetEndOffset()->GetLabelIdx());
245 /* tt */
246 const LSDAActionTable *lsdaActionTable = ehFunc->GetLSDAActionTable();
247 for (size_t i = 0; i < lsdaActionTable->Size(); ++i) {
248 LSDAAction *lsdaAction = lsdaActionTable->GetActionTable().at(i);
249 emitter->Emit("\t.byte ").Emit(lsdaAction->GetActionIndex()).Emit("\n");
250 emitter->Emit("\t.byte ").Emit(lsdaAction->GetActionFilter()).Emit("\n");
251 }
252 emitter->Emit("\t.align 3\n");
253 for (int32 i = ehFunc->GetEHTyTableSize() - 1; i >= 0; i--) {
254 MIRType *mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ehFunc->GetEHTyTableMember(i));
255 MIRTypeKind typeKind = mirType->GetKind();
256 if (((typeKind == kTypeScalar) && (mirType->GetPrimType() == PTY_void)) ||
257 (typeKind == kTypeStructIncomplete) || (typeKind == kTypeInterfaceIncomplete)) {
258 continue;
259 }
260 CHECK_FATAL((typeKind == kTypeClass) || (typeKind == kTypeClassIncomplete), "NYI");
261 const std::string &tyName = GlobalTables::GetStrTable().GetStringFromStrIdx(mirType->GetNameStrIdx());
262 std::string dwRefString(".LDW.ref.");
263 dwRefString += CLASSINFO_PREFIX_STR;
264 dwRefString += tyName;
265 dwRefString += " - .";
266 emitter->Emit("\t.4byte " + dwRefString + "\n");
267 }
268 /* end of lsda */
269 emitter->EmitStmtLabel(lsdaHeader->GetTTypeOffset().GetEndOffset()->GetLabelIdx());
270 }
271
EmitBBHeaderLabel(FuncEmitInfo & funcEmitInfo,const std::string & name,LabelIdx labIdx)272 void AArch64AsmEmitter::EmitBBHeaderLabel(FuncEmitInfo &funcEmitInfo, const std::string &name, LabelIdx labIdx)
273 {
274 (void)name;
275 CGFunc &cgFunc = funcEmitInfo.GetCGFunc();
276 AArch64CGFunc &aarchCGFunc = static_cast<AArch64CGFunc &>(cgFunc);
277 CG *currCG = cgFunc.GetCG();
278 Emitter &emitter = *(currCG->GetEmitter());
279 LabelOperand &label = aarchCGFunc.GetOrCreateLabelOperand(labIdx);
280 /* if label order is default value -1, set new order */
281 if (label.GetLabelOrder() == 0xFFFFFFFF) {
282 label.SetLabelOrder(currCG->GetLabelOrderCnt());
283 currCG->IncreaseLabelOrderCnt();
284 }
285 PUIdx pIdx = currCG->GetMIRModule()->CurFunction()->GetPuidx();
286 char *puIdx = strdup(std::to_string(pIdx).c_str());
287 const std::string &labelName = cgFunc.GetFunction().GetLabelTab()->GetName(labIdx);
288 if (currCG->GenerateVerboseCG()) {
289 (void)emitter.Emit(".L.")
290 .Emit(puIdx)
291 .Emit("__")
292 .Emit(labIdx)
293 .Emit(":\t//label order ")
294 .Emit(label.GetLabelOrder());
295 if (!labelName.empty() && labelName.at(0) != '@') {
296 /* If label name has @ as its first char, it is not from MIR */
297 (void)emitter.Emit(", MIR: @").Emit(labelName).Emit("\n");
298 } else {
299 (void)emitter.Emit("\n");
300 }
301 } else {
302 (void)emitter.Emit(".L.").Emit(puIdx).Emit("__").Emit(labIdx).Emit(":\n");
303 }
304 free(puIdx);
305 puIdx = nullptr;
306 }
307
EmitJavaInsnAddr(FuncEmitInfo & funcEmitInfo)308 void AArch64AsmEmitter::EmitJavaInsnAddr(FuncEmitInfo &funcEmitInfo)
309 {
310 CGFunc &cgFunc = funcEmitInfo.GetCGFunc();
311 if (cgFunc.GetFunction().IsJava()) {
312 Emitter *emitter = cgFunc.GetCG()->GetEmitter();
313 /* emit a comment of current address from the begining of java text section */
314 std::stringstream ss;
315 ss << "\n\t// addr: 0x" << std::hex << (emitter->GetJavaInsnCount() * kInsnSize) << "\n";
316 cgFunc.GetCG()->GetEmitter()->Emit(ss.str());
317 }
318 }
319
RecordRegInfo(FuncEmitInfo & funcEmitInfo) const320 void AArch64AsmEmitter::RecordRegInfo(FuncEmitInfo &funcEmitInfo) const
321 {
322 if (!CGOptions::DoIPARA() || funcEmitInfo.GetCGFunc().GetFunction().IsJava()) {
323 return;
324 }
325 CGFunc &cgFunc = funcEmitInfo.GetCGFunc();
326 AArch64CGFunc &aarchCGFunc = static_cast<AArch64CGFunc &>(cgFunc);
327
328 std::set<regno_t> referedRegs;
329 MIRFunction &mirFunc = cgFunc.GetFunction();
330 FOR_ALL_BB_REV(bb, &aarchCGFunc) {
331 FOR_BB_INSNS_REV(insn, bb) {
332 if (!insn->IsMachineInstruction()) {
333 continue;
334 }
335 if (insn->IsCall() || insn->IsTailCall()) {
336 auto *targetOpnd = insn->GetCallTargetOperand();
337 bool safeCheck = false;
338 CHECK_FATAL(targetOpnd != nullptr,
339 "target is null in AArch64Emitter::IsCallToFunctionThatNeverReturns");
340 if (targetOpnd->IsFuncNameOpnd()) {
341 FuncNameOperand *target = static_cast<FuncNameOperand *>(targetOpnd);
342 const MIRSymbol *funcSt = target->GetFunctionSymbol();
343 DEBUG_ASSERT(funcSt->GetSKind() == maple::kStFunc, "funcst must be a function name symbol");
344 MIRFunction *func = funcSt->GetFunction();
345 if (func != nullptr && func->IsReferedRegsValid()) {
346 safeCheck = true;
347 for (auto preg : func->GetReferedRegs()) {
348 referedRegs.insert(preg);
349 }
350 }
351 }
352 if (!safeCheck) {
353 mirFunc.SetReferedRegsValid(false);
354 return;
355 }
356 }
357 if (referedRegs.size() == kMaxRegNum) {
358 break;
359 }
360 uint32 opndNum = insn->GetOperandSize();
361 const InsnDesc *md = &AArch64CG::kMd[insn->GetMachineOpcode()];
362 for (uint32 i = 0; i < opndNum; ++i) {
363 if (insn->GetMachineOpcode() == MOP_asm) {
364 if (i == kAsmOutputListOpnd || i == kAsmClobberListOpnd) {
365 for (auto opnd : static_cast<ListOperand &>(insn->GetOperand(i)).GetOperands()) {
366 if (opnd->IsRegister()) {
367 referedRegs.insert(static_cast<RegOperand *>(opnd)->GetRegisterNumber());
368 }
369 }
370 }
371 continue;
372 }
373 Operand &opnd = insn->GetOperand(i);
374 if (opnd.IsList()) {
375 /* all use, skip it */
376 } else if (opnd.IsMemoryAccessOperand()) {
377 auto &memOpnd = static_cast<MemOperand &>(opnd);
378 RegOperand *base = memOpnd.GetBaseRegister();
379 if (!memOpnd.IsIntactIndexed()) {
380 referedRegs.insert(base->GetRegisterNumber());
381 }
382 } else if (opnd.IsRegister()) {
383 RegType regType = static_cast<RegOperand &>(opnd).GetRegisterType();
384 if (regType == kRegTyCc || regType == kRegTyVary) {
385 continue;
386 }
387 bool isDef = md->GetOpndDes(i)->IsRegDef();
388 if (isDef) {
389 referedRegs.insert(static_cast<RegOperand &>(opnd).GetRegisterNumber());
390 }
391 }
392 }
393 }
394 }
395 mirFunc.SetReferedRegsValid(true);
396 #ifdef DEBUG
397 for (auto reg : referedRegs) {
398 if (reg > kMaxRegNum) {
399 DEBUG_ASSERT(0, "unexpected preg");
400 }
401 }
402 #endif
403 mirFunc.CopyReferedRegs(referedRegs);
404 }
405
Run(FuncEmitInfo & funcEmitInfo)406 void AArch64AsmEmitter::Run(FuncEmitInfo &funcEmitInfo)
407 {
408 CGFunc &cgFunc = funcEmitInfo.GetCGFunc();
409 AArch64CGFunc &aarchCGFunc = static_cast<AArch64CGFunc &>(cgFunc);
410 CG *currCG = cgFunc.GetCG();
411 /* emit header of this function */
412 Emitter &emitter = *currCG->GetEmitter();
413 // insert for __cxx_global_var_init
414 if (cgFunc.GetName() == "__cxx_global_var_init") {
415 (void)emitter.Emit("\t.section\t.init_array,\"aw\"\n");
416 (void)emitter.Emit("\t.quad\t").Emit(cgFunc.GetName()).Emit("\n");
417 }
418 if (cgFunc.GetFunction().GetAttr(FUNCATTR_initialization)) {
419 (void)emitter.Emit("\t.section\t.init_array,\"aw\"\n");
420 (void)emitter.Emit("\t.quad\t").Emit(cgFunc.GetName()).Emit("\n");
421 }
422 if (cgFunc.GetFunction().GetAttr(FUNCATTR_termination)) {
423 (void)emitter.Emit("\t.section\t.fini_array,\"aw\"\n");
424 (void)emitter.Emit("\t.quad\t").Emit(cgFunc.GetName()).Emit("\n");
425 }
426 (void)emitter.Emit("\n");
427 EmitMethodDesc(funcEmitInfo, emitter);
428 /* emit java code to the java section. */
429 if (cgFunc.GetFunction().IsJava()) {
430 std::string sectionName = namemangler::kMuidJavatextPrefixStr;
431 (void)emitter.Emit("\t.section ." + sectionName + ",\"ax\"\n");
432 } else if (cgFunc.GetFunction().GetAttr(FUNCATTR_section)) {
433 const std::string §ionName = cgFunc.GetFunction().GetAttrs().GetPrefixSectionName();
434 (void)emitter.Emit("\t.section " + sectionName).Emit(",\"ax\",@progbits\n");
435 } else if (CGOptions::IsFunctionSections()) {
436 (void)emitter.Emit("\t.section .text.").Emit(cgFunc.GetName()).Emit(",\"ax\",@progbits\n");
437 } else if (cgFunc.GetFunction().GetAttr(FUNCATTR_constructor_priority)) {
438 (void)emitter.Emit("\t.section\t.text.startup").Emit(",\"ax\",@progbits\n");
439 } else {
440 (void)emitter.Emit("\t.text\n");
441 }
442 if (CGOptions::GetFuncAlignPow() != 0) {
443 (void)emitter.Emit("\t.align ").Emit(CGOptions::GetFuncAlignPow()).Emit("\n");
444 }
445 MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStidx(cgFunc.GetFunction().GetStIdx().Idx());
446 const std::string &funcName = std::string(cgFunc.GetShortFuncName().c_str());
447
448 // manually replace function with optimized assembly language
449 if (CGOptions::IsReplaceASM()) {
450 auto it = func2CodeInsnMap.find(funcSt->GetName());
451 if (it != func2CodeInsnMap.end()) {
452 std::string optFile = it->second.first;
453 struct stat buffer;
454 if (stat(optFile.c_str(), &buffer) == 0) {
455 std::ifstream codetricksFd(optFile);
456 if (!codetricksFd.is_open()) {
457 ERR(kLncErr, " %s open failed!", optFile.c_str());
458 LogInfo::MapleLogger() << "wrong" << '\n';
459 } else {
460 std::string contend;
461 while (getline(codetricksFd, contend)) {
462 (void)emitter.Emit(contend + "\n");
463 }
464 }
465 }
466 emitter.IncreaseJavaInsnCount(it->second.second);
467 #ifdef EMIT_INSN_COUNT
468 EmitJavaInsnAddr(funcEmitInfo);
469 #endif /* ~EMIT_INSN_COUNT */
470 return;
471 }
472 }
473 std::string funcStName = funcSt->GetName();
474 if (funcSt->GetFunction()->GetAttr(FUNCATTR_weak)) {
475 (void)emitter.Emit("\t.weak\t" + funcStName + "\n");
476 (void)emitter.Emit("\t.hidden\t" + funcStName + "\n");
477 } else if (funcSt->GetFunction()->GetAttr(FUNCATTR_local)) {
478 (void)emitter.Emit("\t.local\t" + funcStName + "\n");
479 } else if (funcSt->GetFunction() && (!funcSt->GetFunction()->IsJava()) && funcSt->GetFunction()->IsStatic()) {
480 // nothing
481 } else {
482 /* should refer to function attribute */
483 (void)emitter.Emit("\t.globl\t").Emit(funcSt->GetName()).Emit("\n");
484 if (!currCG->GetMIRModule()->IsCModule()) {
485 (void)emitter.Emit("\t.hidden\t").Emit(funcSt->GetName()).Emit("\n");
486 }
487 }
488 (void)emitter.Emit("\t.type\t" + funcStName + ", %function\n");
489 /* add these messege , solve the performance tool error */
490 EmitRefToMethodDesc(funcEmitInfo, emitter);
491 (void)emitter.Emit(funcStName + ":\n");
492
493 /* if the last insn is call, then insert nop */
494 bool found = false;
495 FOR_ALL_BB_REV(bb, &aarchCGFunc) {
496 FOR_BB_INSNS_REV(insn, bb) {
497 if (insn->IsMachineInstruction()) {
498 if (insn->IsCall()) {
499 Insn &newInsn = aarchCGFunc.GetInsnBuilder()->BuildInsn<AArch64CG>(MOP_nop);
500 bb->InsertInsnAfter(*insn, newInsn);
501 }
502 found = true;
503 break;
504 }
505 }
506 if (found) {
507 break;
508 }
509 }
510
511 RecordRegInfo(funcEmitInfo);
512
513 /* emit instructions */
514 FOR_ALL_BB(bb, &aarchCGFunc) {
515 if (bb->IsUnreachable()) {
516 continue;
517 }
518 if (currCG->GenerateVerboseCG()) {
519 (void)emitter.Emit("# freq:").Emit(bb->GetFrequency()).Emit("\n");
520 }
521 /* emit bb headers */
522 if (bb->GetLabIdx() != MIRLabelTable::GetDummyLabel()) {
523 if (aarchCGFunc.GetMirModule().IsCModule() && bb->IsBBNeedAlign() &&
524 bb->GetAlignNopNum() != kAlignMovedFlag) {
525 uint32 power = bb->GetAlignPower();
526 (void)emitter.Emit("\t.p2align ").Emit(power).Emit("\n");
527 }
528 EmitBBHeaderLabel(funcEmitInfo, funcName, bb->GetLabIdx());
529 }
530
531 FOR_BB_INSNS(insn, bb) {
532 if (insn->IsCfiInsn()) {
533 EmitAArch64CfiInsn(emitter, *insn);
534 } else if (insn->IsDbgInsn()) {
535 EmitAArch64DbgInsn(emitter, *insn);
536 } else {
537 EmitAArch64Insn(emitter, *insn);
538 }
539 }
540 }
541 if (CGOptions::IsMapleLinker()) {
542 /* Emit a label for calculating method size */
543 (void)emitter.Emit(".Label.end." + funcStName + ":\n");
544 }
545 (void)emitter.Emit("\t.size\t" + funcStName + ", .-").Emit(funcStName + "\n");
546
547 auto constructorAttr = funcSt->GetFunction()->GetAttrs().GetConstructorPriority();
548 if (constructorAttr != -1) {
549 (void)emitter.Emit("\t.section\t.init_array." + std::to_string(constructorAttr) + ",\"aw\"\n");
550 (void)emitter.Emit("\t.align 3\n");
551 (void)emitter.Emit("\t.xword\t" + funcStName + "\n");
552 }
553
554 EHFunc *ehFunc = cgFunc.GetEHFunc();
555 /* emit LSDA */
556 if (cgFunc.GetFunction().IsJava() && (ehFunc != nullptr)) {
557 if (!cgFunc.GetHasProEpilogue()) {
558 (void)emitter.Emit("\t.word 0x55555555\n");
559 emitter.IncreaseJavaInsnCount();
560 } else if (ehFunc->NeedFullLSDA()) {
561 LSDAHeader *lsdaHeader = ehFunc->GetLSDAHeader();
562 PUIdx pIdx = emitter.GetCG()->GetMIRModule()->CurFunction()->GetPuidx();
563 const std::string &idx = strdup(std::to_string(pIdx).c_str());
564 /* .word .Label.lsda_label-func_start_label */
565 (void)emitter.Emit("\t.word .L." + idx).Emit("__").Emit(lsdaHeader->GetLSDALabel()->GetLabelIdx());
566 (void)emitter.Emit("-.L." + idx).Emit("__").Emit(cgFunc.GetStartLabel()->GetLabelIdx()).Emit("\n");
567 emitter.IncreaseJavaInsnCount();
568 } else if (ehFunc->NeedFastLSDA()) {
569 EmitFastLSDA(funcEmitInfo);
570 }
571 }
572
573 for (auto &it : cgFunc.GetEmitStVec()) {
574 /* emit switch table only here */
575 MIRSymbol *st = it.second;
576 DEBUG_ASSERT(st->IsReadOnly(), "NYI");
577 (void)emitter.Emit("\n");
578 (void)emitter.Emit("\t.align 3\n");
579 emitter.IncreaseJavaInsnCount(0, true); /* just aligned */
580 (void)emitter.Emit(st->GetName() + ":\n");
581 MIRAggConst *arrayConst = safe_cast<MIRAggConst>(st->GetKonst());
582 CHECK_FATAL(arrayConst != nullptr, "null ptr check");
583 PUIdx pIdx = cgFunc.GetMirModule().CurFunction()->GetPuidx();
584 char *idx = strdup(std::to_string(pIdx).c_str());
585 for (size_t i = 0; i < arrayConst->GetConstVec().size(); i++) {
586 MIRLblConst *lblConst = safe_cast<MIRLblConst>(arrayConst->GetConstVecItem(i));
587 CHECK_FATAL(lblConst != nullptr, "null ptr check");
588 (void)emitter.Emit("\t.quad\t.L.").Emit(idx).Emit("__").Emit(lblConst->GetValue());
589 (void)emitter.Emit(" - " + st->GetName() + "\n");
590 emitter.IncreaseJavaInsnCount(kQuadInsnCount);
591 }
592 free(idx);
593 idx = nullptr;
594 }
595
596 for (const auto &mpPair : cgFunc.GetLabelAndValueMap()) {
597 LabelOperand &labelOpnd = aarchCGFunc.GetOrCreateLabelOperand(mpPair.first);
598 A64OpndEmitVisitor visitor(emitter, nullptr);
599 labelOpnd.Accept(visitor);
600 (void)emitter.Emit(":\n");
601 (void)emitter.Emit("\t.quad ").Emit(static_cast<int64>(mpPair.second)).Emit("\n");
602 emitter.IncreaseJavaInsnCount(kQuadInsnCount);
603 }
604
605 if (ehFunc != nullptr && ehFunc->NeedFullLSDA()) {
606 EmitFullLSDA(funcEmitInfo);
607 }
608 #ifdef EMIT_INSN_COUNT
609 if (cgFunc.GetFunction().IsJava()) {
610 EmitJavaInsnAddr(funcEmitInfo);
611 }
612 #endif /* ~EMIT_INSN_COUNT */
613 }
614
EmitAArch64Insn(maplebe::Emitter & emitter,Insn & insn) const615 void AArch64AsmEmitter::EmitAArch64Insn(maplebe::Emitter &emitter, Insn &insn) const
616 {
617 MOperator mOp = insn.GetMachineOpcode();
618 emitter.SetCurrentMOP(mOp);
619 const InsnDesc *md = insn.GetDesc();
620
621 if (!GetCG()->GenerateVerboseAsm() && !GetCG()->GenerateVerboseCG() && insn.IsComment()) {
622 return;
623 }
624
625 switch (mOp) {
626 case MOP_clinit: {
627 EmitClinit(emitter, insn);
628 emitter.IncreaseJavaInsnCount(md->GetAtomicNum());
629 return;
630 }
631 case MOP_adrp_ldr: {
632 uint32 adrpldrInsnCount = md->GetAtomicNum();
633 emitter.IncreaseJavaInsnCount(adrpldrInsnCount);
634 EmitAdrpLdr(emitter, insn);
635 if (CGOptions::IsLazyBinding() && !GetCG()->IsLibcore()) {
636 EmitLazyBindingRoutine(emitter, insn);
637 emitter.IncreaseJavaInsnCount(adrpldrInsnCount + 1);
638 }
639 return;
640 }
641 case MOP_counter: {
642 EmitCounter(emitter, insn);
643 return;
644 }
645 case MOP_asm: {
646 EmitInlineAsm(emitter, insn);
647 return;
648 }
649 case MOP_clinit_tail: {
650 EmitClinitTail(emitter, insn);
651 emitter.IncreaseJavaInsnCount(md->GetAtomicNum());
652 return;
653 }
654 case MOP_lazy_ldr: {
655 EmitLazyLoad(emitter, insn);
656 emitter.IncreaseJavaInsnCount(md->GetAtomicNum());
657 return;
658 }
659 case MOP_adrp_label: {
660 EmitAdrpLabel(emitter, insn);
661 return;
662 }
663 case MOP_lazy_tail: {
664 /* No need to emit this pseudo instruction. */
665 return;
666 }
667 case MOP_lazy_ldr_static: {
668 EmitLazyLoadStatic(emitter, insn);
669 emitter.IncreaseJavaInsnCount(md->GetAtomicNum());
670 return;
671 }
672 case MOP_arrayclass_cache_ldr: {
673 EmitArrayClassCacheLoad(emitter, insn);
674 emitter.IncreaseJavaInsnCount(md->GetAtomicNum());
675 return;
676 }
677 case MOP_get_and_addI:
678 case MOP_get_and_addL: {
679 EmitGetAndAddInt(emitter, insn);
680 return;
681 }
682 case MOP_get_and_setI:
683 case MOP_get_and_setL: {
684 EmitGetAndSetInt(emitter, insn);
685 return;
686 }
687 case MOP_compare_and_swapI:
688 case MOP_compare_and_swapL: {
689 EmitCompareAndSwapInt(emitter, insn);
690 return;
691 }
692 case MOP_string_indexof: {
693 EmitStringIndexOf(emitter, insn);
694 return;
695 }
696 case MOP_pseudo_none:
697 case MOP_pseduo_tls_release: {
698 return;
699 }
700 case MOP_tls_desc_call: {
701 EmitCTlsDescCall(emitter, insn);
702 return;
703 }
704 case MOP_tls_desc_rel: {
705 EmitCTlsDescRel(emitter, insn);
706 return;
707 }
708 case MOP_sync_lock_test_setI:
709 case MOP_sync_lock_test_setL: {
710 EmitSyncLockTestSet(emitter, insn);
711 return;
712 }
713 default:
714 break;
715 }
716
717 if (CGOptions::IsNativeOpt() && mOp == MOP_xbl) {
718 auto *nameOpnd = static_cast<FuncNameOperand *>(&insn.GetOperand(kInsnFirstOpnd));
719 if (nameOpnd->GetName() == "MCC_CheckThrowPendingException") {
720 EmitCheckThrowPendingException(emitter, insn);
721 emitter.IncreaseJavaInsnCount(md->GetAtomicNum());
722 return;
723 }
724 }
725
726 std::string format(md->format);
727 (void)emitter.Emit("\t").Emit(md->name).Emit("\t");
728 size_t opndSize = insn.GetOperandSize();
729 std::vector<int32> seq(opndSize, -1);
730 std::vector<std::string> prefix(opndSize); /* used for print prefix like "*" in icall *rax */
731 uint32 index = 0;
732 uint32 commaNum = 0;
733 for (uint32 i = 0; i < format.length(); ++i) {
734 char c = format[i];
735 if (c >= '0' && c <= '5') {
736 seq[index++] = c - '0';
737 ++commaNum;
738 } else if (c != ',') {
739 prefix[index].push_back(c);
740 }
741 }
742
743 bool isRefField =
744 (opndSize == 0) ? false : CheckInsnRefField(insn, static_cast<size_t>(static_cast<uint32>(seq[0])));
745 if (insn.IsComment()) {
746 emitter.IncreaseJavaInsnCount();
747 }
748 uint32 compositeOpnds = 0;
749 for (uint32 i = 0; i < commaNum; ++i) {
750 if (seq[i] == -1) {
751 continue;
752 }
753 if (prefix[i].length() > 0) {
754 (void)emitter.Emit(prefix[i]);
755 }
756 if (emitter.NeedToDealWithHugeSo() && (mOp == MOP_xbl || mOp == MOP_tail_call_opt_xbl)) {
757 auto *nameOpnd = static_cast<FuncNameOperand *>(&insn.GetOperand(kInsnFirstOpnd));
758 /* Suport huge so here
759 * As the PLT section is just before java_text section, when java_text section is larger
760 * then 128M, instrunction of "b" and "bl" would fault to branch to PLT stub functions. Here, to save
761 * instuctions space, we change the branch target to a local target within 120M address, and add non-plt
762 * call to the target function.
763 */
764 emitter.InsertHugeSoTarget(nameOpnd->GetName());
765 (void)emitter.Emit(nameOpnd->GetName() + emitter.HugeSoPostFix());
766 break;
767 }
768 auto *opnd = &insn.GetOperand(static_cast<uint32>(seq[i]));
769 if (opnd && opnd->IsRegister()) {
770 auto *regOpnd = static_cast<RegOperand *>(opnd);
771 if ((md->opndMD[static_cast<uint32>(seq[i])])->IsVectorOperand()) {
772 regOpnd->SetVecLanePosition(-1);
773 regOpnd->SetVecLaneSize(0);
774 regOpnd->SetVecElementSize(0);
775 if (insn.IsVectorOp()) {
776 PrepareVectorOperand(regOpnd, compositeOpnds, insn);
777 if (compositeOpnds != 0) {
778 (void)emitter.Emit("{");
779 }
780 }
781 }
782 }
783 A64OpndEmitVisitor visitor(emitter, md->opndMD[static_cast<uint32>(seq[i])]);
784
785 insn.GetOperand(static_cast<uint32>(seq[i])).Accept(visitor);
786 if (compositeOpnds == 1) {
787 (void)emitter.Emit("}");
788 }
789 if (compositeOpnds > 0) {
790 --compositeOpnds;
791 }
792 /* reset opnd0 ref-field flag, so following instruction has correct register */
793 if (isRefField && (i == 0)) {
794 static_cast<RegOperand *>(&insn.GetOperand(static_cast<uint32>(seq[0])))->SetRefField(false);
795 }
796 /* Temporary comment the label:.Label.debug.callee */
797 if (i != (commaNum - 1)) {
798 (void)emitter.Emit(", ");
799 }
800 const uint32 commaNumForEmitLazy = 2;
801 if (!CGOptions::IsLazyBinding() || GetCG()->IsLibcore() || (mOp != MOP_wldr && mOp != MOP_xldr) ||
802 commaNum != commaNumForEmitLazy || i != 1 ||
803 !insn.GetOperand(static_cast<uint32>(seq[1])).IsMemoryAccessOperand()) {
804 continue;
805 }
806 /*
807 * Only check the last operand of ldr in lo12 mode.
808 * Check the second operand, if it's [AArch64MemOperand::kAddrModeLo12Li]
809 */
810 auto *memOpnd = static_cast<MemOperand *>(&insn.GetOperand(static_cast<uint32>(seq[1])));
811 if (memOpnd == nullptr || memOpnd->GetAddrMode() != MemOperand::kAddrModeLo12Li) {
812 continue;
813 }
814 const MIRSymbol *sym = memOpnd->GetSymbol();
815 if (sym->IsMuidFuncDefTab() || sym->IsMuidFuncUndefTab() || sym->IsMuidDataDefTab() ||
816 sym->IsMuidDataUndefTab()) {
817 (void)emitter.Emit("\n");
818 EmitLazyBindingRoutine(emitter, insn);
819 emitter.IncreaseJavaInsnCount(1);
820 }
821 }
822 if (GetCG()->GenerateVerboseCG() || (GetCG()->GenerateVerboseAsm() && insn.IsComment())) {
823 const char *comment = insn.GetComment().c_str();
824 if (comment != nullptr && strlen(comment) > 0) {
825 (void)emitter.Emit("\t\t// ").Emit(comment);
826 }
827 }
828
829 (void)emitter.Emit("\n");
830 }
831
EmitClinit(Emitter & emitter,const Insn & insn) const832 void AArch64AsmEmitter::EmitClinit(Emitter &emitter, const Insn &insn) const
833 {
834 /*
835 * adrp x3, __muid_data_undef_tab$$GetBoolean_bytecode+144
836 * ldr x3, [x3, #:lo12:__muid_data_undef_tab$$GetBoolean_bytecode+144]
837 * or,
838 * adrp x3, _PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B
839 * ldr x3, [x3, #:lo12:_PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B]
840 *
841 * ldr x3, [x3,#112]
842 * ldr wzr, [x3]
843 */
844 const InsnDesc *md = &AArch64CG::kMd[MOP_clinit];
845
846 Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
847 Operand *opnd1 = &insn.GetOperand(kInsnSecondOpnd);
848 const OpndDesc *prop0 = md->opndMD[0];
849 A64OpndEmitVisitor visitor(emitter, prop0);
850 auto *stImmOpnd = static_cast<StImmOperand *>(opnd1);
851 CHECK_FATAL(stImmOpnd != nullptr, "stImmOpnd is null in AArch64Emitter::EmitClinit");
852 /* emit nop for breakpoint */
853 if (GetCG()->GetCGOptions().WithDwarf()) {
854 (void)emitter.Emit("\t").Emit("nop").Emit("\n");
855 }
856
857 if (stImmOpnd->GetSymbol()->IsMuidDataUndefTab()) {
858 /* emit adrp */
859 (void)emitter.Emit("\t").Emit("adrp").Emit("\t");
860 opnd0->Accept(visitor);
861 (void)emitter.Emit(",");
862 (void)emitter.Emit(stImmOpnd->GetName());
863 (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
864 (void)emitter.Emit("\n");
865 /* emit ldr */
866 (void)emitter.Emit("\t").Emit("ldr").Emit("\t");
867 opnd0->Accept(visitor);
868 (void)emitter.Emit(",");
869 (void)emitter.Emit("[");
870 opnd0->Accept(visitor);
871 (void)emitter.Emit(",");
872 (void)emitter.Emit("#");
873 (void)emitter.Emit(":lo12:").Emit(stImmOpnd->GetName());
874 (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
875 (void)emitter.Emit("]");
876 (void)emitter.Emit("\n");
877 } else {
878 /* adrp x3, _PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B */
879 (void)emitter.Emit("\tadrp\t");
880 opnd0->Accept(visitor);
881 (void)emitter.Emit(",");
882 (void)emitter.Emit(namemangler::kPtrPrefixStr + stImmOpnd->GetName());
883 (void)emitter.Emit("\n");
884
885 /* ldr x3, [x3, #:lo12:_PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B] */
886 (void)emitter.Emit("\tldr\t");
887 opnd0->Accept(visitor);
888 (void)emitter.Emit(", [");
889 opnd0->Accept(visitor);
890 (void)emitter.Emit(", #:lo12:");
891 (void)emitter.Emit(namemangler::kPtrPrefixStr + stImmOpnd->GetName());
892 (void)emitter.Emit("]\n");
893 }
894 /* emit "ldr x0,[x0,#48]" */
895 (void)emitter.Emit("\t").Emit("ldr").Emit("\t");
896 opnd0->Accept(visitor);
897 (void)emitter.Emit(",");
898 (void)emitter.Emit("[");
899 opnd0->Accept(visitor);
900 (void)emitter.Emit(",#");
901 (void)emitter.Emit(static_cast<uint32>(ClassMetadata::OffsetOfInitState()));
902 (void)emitter.Emit("]");
903 (void)emitter.Emit("\n");
904
905 /* emit "ldr xzr, [x0]" */
906 (void)emitter.Emit("\t").Emit("ldr\txzr, [");
907 opnd0->Accept(visitor);
908 (void)emitter.Emit("]\n");
909 }
910
AsmStringOutputRegNum(bool isInt,uint32 regno,uint32 intBase,uint32 fpBase,std::string & strToEmit)911 static void AsmStringOutputRegNum(bool isInt, uint32 regno, uint32 intBase, uint32 fpBase, std::string &strToEmit)
912 {
913 regno_t newRegno;
914 if (isInt) {
915 newRegno = regno - intBase;
916 } else {
917 newRegno = regno - fpBase;
918 }
919 if (newRegno > (kDecimalMax - 1)) {
920 uint32 tenth = newRegno / kDecimalMax;
921 strToEmit += '0' + static_cast<char>(tenth);
922 newRegno -= (kDecimalMax * tenth);
923 }
924 strToEmit += newRegno + '0';
925 }
926
EmitInlineAsm(Emitter & emitter,const Insn & insn) const927 void AArch64AsmEmitter::EmitInlineAsm(Emitter &emitter, const Insn &insn) const
928 {
929 (void)emitter.Emit("\t//Inline asm begin\n\t");
930 auto &list1 = static_cast<ListOperand &>(insn.GetOperand(kAsmOutputListOpnd));
931 std::vector<RegOperand *> outOpnds;
932 for (auto *regOpnd : list1.GetOperands()) {
933 outOpnds.push_back(regOpnd);
934 }
935 auto &list2 = static_cast<ListOperand &>(insn.GetOperand(kAsmInputListOpnd));
936 std::vector<RegOperand *> inOpnds;
937 for (auto *regOpnd : list2.GetOperands()) {
938 inOpnds.push_back(regOpnd);
939 }
940 auto &list6 = static_cast<ListConstraintOperand &>(insn.GetOperand(kAsmOutputRegPrefixOpnd));
941 auto &list7 = static_cast<ListConstraintOperand &>(insn.GetOperand(kAsmInputRegPrefixOpnd));
942 MapleString asmStr = static_cast<StringOperand &>(insn.GetOperand(kAsmStringOpnd)).GetComment();
943 std::string stringToEmit;
944 auto IsMemAccess = [](char c) -> bool { return c == '['; };
945 auto EmitRegister = [&](const char *p, bool isInt, uint32 regNO, bool unDefRegSize) -> void {
946 if (IsMemAccess(p[0])) {
947 stringToEmit += "[x";
948 AsmStringOutputRegNum(isInt, regNO, R0, V0, stringToEmit);
949 stringToEmit += "]";
950 } else {
951 DEBUG_ASSERT((p[0] == 'w' || p[0] == 'x' || p[0] == 's' || p[0] == 'd' || p[0] == 'v'),
952 "Asm invalid register type");
953 if ((p[0] == 'w' || p[0] == 'x') && unDefRegSize) {
954 stringToEmit += 'x';
955 } else {
956 stringToEmit += p[0];
957 }
958 if (!unDefRegSize) {
959 isInt = (p[0] == 'w' || p[0] == 'x');
960 }
961 AsmStringOutputRegNum(isInt, regNO, R0, V0, stringToEmit);
962 }
963 };
964 for (size_t i = 0; i < asmStr.length(); ++i) {
965 switch (asmStr[i]) {
966 case '$': {
967 char c = asmStr[++i];
968 if ((c >= '0') && (c <= '9')) {
969 auto val = static_cast<uint32>(c - '0');
970 if (asmStr[i + 1] >= '0' && asmStr[i + 1] <= '9') {
971 val = val * kDecimalMax + static_cast<uint32>(asmStr[++i] - '0');
972 }
973 if (val < outOpnds.size()) {
974 const char *prefix = list6.stringList[val]->GetComment().c_str();
975 RegOperand *opnd = outOpnds[val];
976 EmitRegister(prefix, opnd->IsOfIntClass(), opnd->GetRegisterNumber(), true);
977 } else {
978 val -= static_cast<uint32>(outOpnds.size());
979 CHECK_FATAL(val < inOpnds.size(), "Inline asm : invalid register constraint number");
980 RegOperand *opnd = inOpnds[val];
981 /* input is a immediate */
982 const char *prefix = list7.stringList[val]->GetComment().c_str();
983 if (prefix[0] == 'i') {
984 stringToEmit += '#';
985 for (size_t k = 1; k < list7.stringList[val]->GetComment().length(); ++k) {
986 stringToEmit += prefix[k];
987 }
988 } else {
989 EmitRegister(prefix, opnd->IsOfIntClass(), opnd->GetRegisterNumber(), true);
990 }
991 }
992 } else if (c == '{') {
993 c = asmStr[++i];
994 CHECK_FATAL(((c >= '0') && (c <= '9')), "Inline asm : invalid register constraint number");
995 auto val = static_cast<uint32>(c - '0');
996 if (asmStr[i + 1] >= '0' && asmStr[i + 1] <= '9') {
997 val = val * kDecimalMax + static_cast<uint32>(asmStr[++i] - '0');
998 }
999 regno_t regno;
1000 bool isAddr = false;
1001 if (val < outOpnds.size()) {
1002 RegOperand *opnd = outOpnds[val];
1003 regno = opnd->GetRegisterNumber();
1004 isAddr = IsMemAccess(list6.stringList[val]->GetComment().c_str()[0]);
1005 } else {
1006 val -= static_cast<uint32>(outOpnds.size());
1007 CHECK_FATAL(val < inOpnds.size(), "Inline asm : invalid register constraint number");
1008 RegOperand *opnd = inOpnds[val];
1009 regno = opnd->GetRegisterNumber();
1010 isAddr = IsMemAccess(list7.stringList[val]->GetComment().c_str()[0]);
1011 }
1012 c = asmStr[++i];
1013 CHECK_FATAL(c == ':', "Parsing error in inline asm string during emit");
1014 c = asmStr[++i];
1015 std::string prefix(1, c);
1016 if (c == 'a' || isAddr) {
1017 prefix = "[x";
1018 }
1019 EmitRegister(prefix.c_str(), true, regno, false);
1020 c = asmStr[++i];
1021 CHECK_FATAL(c == '}', "Parsing error in inline asm string during emit");
1022 }
1023 break;
1024 }
1025 case '\n': {
1026 stringToEmit += "\n\t";
1027 break;
1028 }
1029 default:
1030 stringToEmit += asmStr[i];
1031 }
1032 }
1033 (void)emitter.Emit(stringToEmit);
1034 (void)emitter.Emit("\n\t//Inline asm end\n");
1035 }
1036
EmitClinitTail(Emitter & emitter,const Insn & insn) const1037 void AArch64AsmEmitter::EmitClinitTail(Emitter &emitter, const Insn &insn) const
1038 {
1039 /*
1040 * ldr x17, [xs, #112]
1041 * ldr wzr, [x17]
1042 */
1043 const InsnDesc *md = &AArch64CG::kMd[MOP_clinit_tail];
1044
1045 Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
1046
1047 const OpndDesc *prop0 = md->opndMD[0];
1048 A64OpndEmitVisitor visitor(emitter, prop0);
1049
1050 /* emit "ldr x17,[xs,#112]" */
1051 (void)emitter.Emit("\t").Emit("ldr").Emit("\tx17, [");
1052 opnd0->Accept(visitor);
1053 (void)emitter.Emit(", #");
1054 (void)emitter.Emit(static_cast<uint32>(ClassMetadata::OffsetOfInitState()));
1055 (void)emitter.Emit("]");
1056 (void)emitter.Emit("\n");
1057
1058 /* emit "ldr xzr, [x17]" */
1059 (void)emitter.Emit("\t").Emit("ldr\txzr, [x17]\n");
1060 }
1061
EmitLazyLoad(Emitter & emitter,const Insn & insn) const1062 void AArch64AsmEmitter::EmitLazyLoad(Emitter &emitter, const Insn &insn) const
1063 {
1064 /*
1065 * ldr wd, [xs] # xd and xs should be differenct register
1066 * ldr wd, [xd]
1067 */
1068 const InsnDesc *md = &AArch64CG::kMd[MOP_lazy_ldr];
1069
1070 Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
1071 Operand *opnd1 = &insn.GetOperand(kInsnSecondOpnd);
1072 const OpndDesc *prop0 = md->opndMD[0];
1073 const OpndDesc *prop1 = md->opndMD[1];
1074 A64OpndEmitVisitor visitor(emitter, prop0);
1075 A64OpndEmitVisitor visitor1(emitter, prop1);
1076
1077 /* emit "ldr wd, [xs]" */
1078 (void)emitter.Emit("\t").Emit("ldr\t");
1079 #ifdef USE_32BIT_REF
1080 opnd0->Accept(visitor);
1081 #else
1082 opnd0->Accept(visitor1);
1083 #endif
1084 (void)emitter.Emit(", [");
1085 opnd1->Accept(visitor1);
1086 (void)emitter.Emit("]\t// lazy load.\n");
1087
1088 /* emit "ldr wd, [xd]" */
1089 (void)emitter.Emit("\t").Emit("ldr\t");
1090 opnd0->Accept(visitor);
1091 (void)emitter.Emit(", [");
1092 opnd1->Accept(visitor1);
1093 (void)emitter.Emit("]\t// lazy load.\n");
1094 }
1095
EmitCounter(Emitter & emitter,const Insn & insn) const1096 void AArch64AsmEmitter::EmitCounter(Emitter &emitter, const Insn &insn) const
1097 {
1098 /*
1099 * adrp x1, __profile_bb_table$$GetBoolean_bytecode+4
1100 * ldr w17, [x1, #:lo12:__profile_bb_table$$GetBoolean_bytecode+4]
1101 * add w17, w17, #1
1102 * str w17, [x1, #:lo12:__profile_bb_table$$GetBoolean_bytecode+4]
1103 */
1104 const InsnDesc *md = &AArch64CG::kMd[MOP_counter];
1105
1106 Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
1107 Operand *opnd1 = &insn.GetOperand(kInsnSecondOpnd);
1108 const OpndDesc *prop0 = md->opndMD[kInsnFirstOpnd];
1109 A64OpndEmitVisitor visitor(emitter, prop0);
1110 StImmOperand *stImmOpnd = static_cast<StImmOperand *>(opnd1);
1111 CHECK_FATAL(stImmOpnd != nullptr, "stImmOpnd is null in AArch64Emitter::EmitCounter");
1112 /* emit nop for breakpoint */
1113 if (GetCG()->GetCGOptions().WithDwarf()) {
1114 (void)emitter.Emit("\t").Emit("nop").Emit("\n");
1115 }
1116
1117 /* emit adrp */
1118 (void)emitter.Emit("\t").Emit("adrp").Emit("\t");
1119 opnd0->Accept(visitor);
1120 (void)emitter.Emit(",");
1121 (void)emitter.Emit(stImmOpnd->GetName());
1122 (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
1123 (void)emitter.Emit("\n");
1124 /* emit ldr */
1125 (void)emitter.Emit("\t").Emit("ldr").Emit("\tw17, [");
1126 opnd0->Accept(visitor);
1127 (void)emitter.Emit(",");
1128 (void)emitter.Emit("#");
1129 (void)emitter.Emit(":lo12:").Emit(stImmOpnd->GetName());
1130 (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
1131 (void)emitter.Emit("]");
1132 (void)emitter.Emit("\n");
1133 /* emit add */
1134 (void)emitter.Emit("\t").Emit("add").Emit("\tw17, w17, #1");
1135 (void)emitter.Emit("\n");
1136 /* emit str */
1137 (void)emitter.Emit("\t").Emit("str").Emit("\tw17, [");
1138 opnd0->Accept(visitor);
1139 (void)emitter.Emit(",");
1140 (void)emitter.Emit("#");
1141 (void)emitter.Emit(":lo12:").Emit(stImmOpnd->GetName());
1142 (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
1143 (void)emitter.Emit("]");
1144 (void)emitter.Emit("\n");
1145 }
1146
EmitAdrpLabel(Emitter & emitter,const Insn & insn) const1147 void AArch64AsmEmitter::EmitAdrpLabel(Emitter &emitter, const Insn &insn) const
1148 {
1149 /* adrp xd, label
1150 * add xd, xd, #lo12:label
1151 */
1152 const InsnDesc *md = &AArch64CG::kMd[MOP_adrp_label];
1153
1154 Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
1155 Operand *opnd1 = &insn.GetOperand(kInsnSecondOpnd);
1156 const OpndDesc *prop0 = md->opndMD[0];
1157 A64OpndEmitVisitor visitor(emitter, prop0);
1158 auto lidx = static_cast<ImmOperand *>(opnd1)->GetValue();
1159
1160 /* adrp xd, label */
1161 (void)emitter.Emit("\t").Emit("adrp").Emit("\t");
1162 opnd0->Accept(visitor);
1163 (void)emitter.Emit(", ");
1164 char *idx;
1165 idx =
1166 strdup(std::to_string(Globals::GetInstance()->GetBECommon()->GetMIRModule().CurFunction()->GetPuidx()).c_str());
1167 (void)emitter.Emit(".L.").Emit(idx).Emit("__").Emit(lidx).Emit("\n");
1168
1169 /* add xd, xd, #lo12:label */
1170 (void)emitter.Emit("\tadd\t");
1171 opnd0->Accept(visitor);
1172 (void)emitter.Emit(", ");
1173 opnd0->Accept(visitor);
1174 (void)emitter.Emit(", ");
1175 (void)emitter.Emit(":lo12:").Emit(".L.").Emit(idx).Emit("__").Emit(lidx).Emit("\n");
1176 (void)emitter.Emit("\n");
1177 free(idx);
1178 idx = nullptr;
1179 }
1180
EmitAdrpLdr(Emitter & emitter,const Insn & insn) const1181 void AArch64AsmEmitter::EmitAdrpLdr(Emitter &emitter, const Insn &insn) const
1182 {
1183 /*
1184 * adrp xd, _PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B
1185 * ldr xd, [xd, #:lo12:_PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B]
1186 */
1187 const InsnDesc *md = &AArch64CG::kMd[MOP_adrp_ldr];
1188 Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
1189 Operand *opnd1 = &insn.GetOperand(kInsnSecondOpnd);
1190 const OpndDesc *prop0 = md->opndMD[0];
1191 A64OpndEmitVisitor visitor(emitter, prop0);
1192 auto *stImmOpnd = static_cast<StImmOperand *>(opnd1);
1193 CHECK_FATAL(stImmOpnd != nullptr, "stImmOpnd is null in AArch64Emitter::EmitAdrpLdr");
1194 /* emit nop for breakpoint */
1195 if (GetCG()->GetCGOptions().WithDwarf()) {
1196 (void)emitter.Emit("\t").Emit("nop").Emit("\n");
1197 }
1198
1199 /* adrp xd, _PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B */
1200 (void)emitter.Emit("\t").Emit("adrp").Emit("\t");
1201 opnd0->Accept(visitor);
1202 (void)emitter.Emit(", ");
1203 (void)emitter.Emit(stImmOpnd->GetName());
1204 if (stImmOpnd->GetOffset() != 0) {
1205 (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
1206 }
1207 (void)emitter.Emit("\n");
1208
1209 /* ldr xd, [xd, #:lo12:_PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B] */
1210 (void)emitter.Emit("\tldr\t");
1211 static_cast<RegOperand *>(opnd0)->SetRefField(true);
1212 opnd0->Accept(visitor);
1213 static_cast<RegOperand *>(opnd0)->SetRefField(false);
1214 (void)emitter.Emit(", ");
1215 (void)emitter.Emit("[");
1216 opnd0->Accept(visitor);
1217 (void)emitter.Emit(",");
1218 (void)emitter.Emit("#");
1219 (void)emitter.Emit(":lo12:").Emit(stImmOpnd->GetName());
1220 if (stImmOpnd->GetOffset() != 0) {
1221 (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
1222 }
1223 (void)emitter.Emit("]\n");
1224 }
1225
EmitLazyLoadStatic(Emitter & emitter,const Insn & insn) const1226 void AArch64AsmEmitter::EmitLazyLoadStatic(Emitter &emitter, const Insn &insn) const
1227 {
1228 /* adrp xd, :got:__staticDecoupleValueOffset$$xxx+offset
1229 * ldr wd, [xd, #:got_lo12:__staticDecoupleValueOffset$$xxx+offset]
1230 * ldr wzr, [xd]
1231 */
1232 const InsnDesc *md = &AArch64CG::kMd[MOP_lazy_ldr_static];
1233
1234 Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
1235 Operand *opnd1 = &insn.GetOperand(kInsnSecondOpnd);
1236 const OpndDesc *prop0 = md->GetOpndDes(0);
1237 A64OpndEmitVisitor visitor(emitter, prop0);
1238 auto *stImmOpnd = static_cast<StImmOperand *>(opnd1);
1239 CHECK_FATAL(stImmOpnd != nullptr, "stImmOpnd is null in AArch64Emitter::EmitLazyLoadStatic");
1240
1241 /* emit "adrp xd, :got:__staticDecoupleValueOffset$$xxx+offset" */
1242 (void)emitter.Emit("\t").Emit("adrp").Emit("\t");
1243 opnd0->Accept(visitor);
1244 (void)emitter.Emit(", ");
1245 (void)emitter.Emit(stImmOpnd->GetName());
1246 if (stImmOpnd->GetOffset() != 0) {
1247 (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
1248 }
1249 (void)emitter.Emit("\t// lazy load static.\n");
1250
1251 /* emit "ldr wd, [xd, #:got_lo12:__staticDecoupleValueOffset$$xxx+offset]" */
1252 (void)emitter.Emit("\tldr\t");
1253 static_cast<RegOperand *>(opnd0)->SetRefField(true);
1254 #ifdef USE_32BIT_REF
1255 const OpndDesc prop2(prop0->GetOperandType(), prop0->GetRegProp(), prop0->GetSize() / 2);
1256 opnd0->Emit(emitter, &prop2); /* ldr wd, ... for terminal system */
1257 #else
1258 opnd0->Accept(visitor); /* ldr xd, ... for qemu */
1259 #endif /* USE_32BIT_REF */
1260 static_cast<RegOperand *>(opnd0)->SetRefField(false);
1261 (void)emitter.Emit(", ");
1262 (void)emitter.Emit("[");
1263 opnd0->Accept(visitor);
1264 (void)emitter.Emit(",");
1265 (void)emitter.Emit("#");
1266 (void)emitter.Emit(":lo12:").Emit(stImmOpnd->GetName());
1267 if (stImmOpnd->GetOffset() != 0) {
1268 (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
1269 }
1270 (void)emitter.Emit("]\t// lazy load static.\n");
1271
1272 /* emit "ldr wzr, [xd]" */
1273 (void)emitter.Emit("\t").Emit("ldr\twzr, [");
1274 opnd0->Accept(visitor);
1275 (void)emitter.Emit("]\t// lazy load static.\n");
1276 }
1277
EmitArrayClassCacheLoad(Emitter & emitter,const Insn & insn) const1278 void AArch64AsmEmitter::EmitArrayClassCacheLoad(Emitter &emitter, const Insn &insn) const
1279 {
1280 /* adrp xd, :got:__arrayClassCacheTable$$xxx+offset
1281 * ldr wd, [xd, #:got_lo12:__arrayClassCacheTable$$xxx+offset]
1282 * ldr wzr, [xd]
1283 */
1284 const InsnDesc *md = &AArch64CG::kMd[MOP_arrayclass_cache_ldr];
1285 Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
1286 Operand *opnd1 = &insn.GetOperand(kInsnSecondOpnd);
1287 const OpndDesc *prop0 = md->GetOpndDes(kInsnFirstOpnd);
1288 A64OpndEmitVisitor visitor(emitter, prop0);
1289 auto *stImmOpnd = static_cast<StImmOperand *>(opnd1);
1290 CHECK_FATAL(stImmOpnd != nullptr, "stImmOpnd is null in AArch64Emitter::EmitLazyLoadStatic");
1291
1292 /* emit "adrp xd, :got:__arrayClassCacheTable$$xxx+offset" */
1293 (void)emitter.Emit("\t").Emit("adrp").Emit("\t");
1294 opnd0->Accept(visitor);
1295 (void)emitter.Emit(", ");
1296 (void)emitter.Emit(stImmOpnd->GetName());
1297 if (stImmOpnd->GetOffset() != 0) {
1298 (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
1299 }
1300 (void)emitter.Emit("\t// load array class.\n");
1301
1302 /* emit "ldr wd, [xd, #:got_lo12:__arrayClassCacheTable$$xxx+offset]" */
1303 (void)emitter.Emit("\tldr\t");
1304 static_cast<RegOperand *>(opnd0)->SetRefField(true);
1305 #ifdef USE_32BIT_REF
1306 const OpndDesc prop2(prop0->GetOperandType(), prop0->GetRegProp(), prop0->GetSize() / 2);
1307 A64OpndEmitVisitor visitor2(emitter, prop2);
1308 opnd0->Accept(visitor2); /* ldr wd, ... for terminal system */
1309 #else
1310 opnd0->Accept(visitor); /* ldr xd, ... for qemu */
1311 #endif /* USE_32BIT_REF */
1312 static_cast<RegOperand *>(opnd0)->SetRefField(false);
1313 (void)emitter.Emit(", ");
1314 (void)emitter.Emit("[");
1315 opnd0->Accept(visitor);
1316 (void)emitter.Emit(",");
1317 (void)emitter.Emit("#");
1318 (void)emitter.Emit(":lo12:").Emit(stImmOpnd->GetName());
1319 if (stImmOpnd->GetOffset() != 0) {
1320 (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
1321 }
1322 (void)emitter.Emit("]\t// load array class.\n");
1323
1324 /* emit "ldr wzr, [xd]" */
1325 (void)emitter.Emit("\t").Emit("ldr\twzr, [");
1326 opnd0->Accept(visitor);
1327 (void)emitter.Emit("]\t// check resolve array class.\n");
1328 }
1329
1330 /*
1331 * intrinsic_get_add_int w0, xt, wt, ws, x1, x2, w3, label
1332 * add xt, x1, x2
1333 * label:
1334 * ldaxr w0, [xt]
1335 * add wt, w0, w3
1336 * stlxr ws, wt, [xt]
1337 * cbnz ws, label
1338 */
EmitGetAndAddInt(Emitter & emitter,const Insn & insn) const1339 void AArch64AsmEmitter::EmitGetAndAddInt(Emitter &emitter, const Insn &insn) const
1340 {
1341 DEBUG_ASSERT(insn.GetOperandSize() > kInsnEighthOpnd, "ensure the oprands number");
1342 (void)emitter.Emit("\t//\tstart of Unsafe.getAndAddInt.\n");
1343 Operand *tempOpnd0 = &insn.GetOperand(kInsnSecondOpnd);
1344 Operand *tempOpnd1 = &insn.GetOperand(kInsnThirdOpnd);
1345 Operand *tempOpnd2 = &insn.GetOperand(kInsnFourthOpnd);
1346 Operand *objOpnd = &insn.GetOperand(kInsnFifthOpnd);
1347 Operand *offsetOpnd = &insn.GetOperand(kInsnSixthOpnd);
1348 Operand *deltaOpnd = &insn.GetOperand(kInsnSeventhOpnd);
1349 Operand *labelOpnd = &insn.GetOperand(kInsnEighthOpnd);
1350 A64OpndEmitVisitor visitor(emitter, nullptr);
1351 /* emit add. */
1352 (void)emitter.Emit("\t").Emit("add").Emit("\t");
1353 tempOpnd0->Accept(visitor);
1354 (void)emitter.Emit(", ");
1355 objOpnd->Accept(visitor);
1356 (void)emitter.Emit(", ");
1357 offsetOpnd->Accept(visitor);
1358 (void)emitter.Emit("\n");
1359 /* emit label. */
1360 labelOpnd->Accept(visitor);
1361 (void)emitter.Emit(":\n");
1362 Operand *retVal = &insn.GetOperand(kInsnFirstOpnd);
1363 const MOperator mOp = insn.GetMachineOpcode();
1364 const InsnDesc *md = &AArch64CG::kMd[mOp];
1365 const OpndDesc *retProp = md->opndMD[kInsnFirstOpnd];
1366 A64OpndEmitVisitor retVisitor(emitter, retProp);
1367 /* emit ldaxr */
1368 (void)emitter.Emit("\t").Emit("ldaxr").Emit("\t");
1369 retVal->Accept(retVisitor);
1370 (void)emitter.Emit(", [");
1371 tempOpnd0->Accept(visitor);
1372 (void)emitter.Emit("]\n");
1373 /* emit add. */
1374 (void)emitter.Emit("\t").Emit("add").Emit("\t");
1375 tempOpnd1->Accept(retVisitor);
1376 (void)emitter.Emit(", ");
1377 retVal->Accept(retVisitor);
1378 (void)emitter.Emit(", ");
1379 deltaOpnd->Accept(retVisitor);
1380 (void)emitter.Emit("\n");
1381 /* emit stlxr. */
1382 (void)emitter.Emit("\t").Emit("stlxr").Emit("\t");
1383 tempOpnd2->Accept(visitor);
1384 (void)emitter.Emit(", ");
1385 tempOpnd1->Accept(retVisitor);
1386 (void)emitter.Emit(", [");
1387 tempOpnd0->Accept(visitor);
1388 (void)emitter.Emit("]\n");
1389 /* emit cbnz. */
1390 (void)emitter.Emit("\t").Emit("cbnz").Emit("\t");
1391 tempOpnd2->Accept(visitor);
1392 (void)emitter.Emit(", ");
1393 labelOpnd->Accept(visitor);
1394 (void)emitter.Emit("\n");
1395 (void)emitter.Emit("\t//\tend of Unsafe.getAndAddInt.\n");
1396 }
1397
1398 /*
1399 * intrinsic_get_set_int w0, xt, ws, x1, x2, w3, label
1400 * add xt, x1, x2
1401 * label:
1402 * ldaxr w0, [xt]
1403 * stlxr ws, w3, [xt]
1404 * cbnz ws, label
1405 */
EmitGetAndSetInt(Emitter & emitter,const Insn & insn) const1406 void AArch64AsmEmitter::EmitGetAndSetInt(Emitter &emitter, const Insn &insn) const
1407 {
1408 /* MOP_get_and_setI and MOP_get_and_setL have 7 operands */
1409 DEBUG_ASSERT(insn.GetOperandSize() > kInsnSeventhOpnd, "ensure the operands number");
1410 Operand *tempOpnd0 = &insn.GetOperand(kInsnSecondOpnd);
1411 Operand *tempOpnd1 = &insn.GetOperand(kInsnThirdOpnd);
1412 Operand *objOpnd = &insn.GetOperand(kInsnFourthOpnd);
1413 Operand *offsetOpnd = &insn.GetOperand(kInsnFifthOpnd);
1414 A64OpndEmitVisitor visitor(emitter, nullptr);
1415 /* add x1, x1, x2 */
1416 (void)emitter.Emit("\tadd\t");
1417 tempOpnd0->Accept(visitor);
1418 (void)emitter.Emit(", ");
1419 objOpnd->Accept(visitor);
1420 (void)emitter.Emit(", ");
1421 offsetOpnd->Accept(visitor);
1422 (void)emitter.Emit("\n");
1423 Operand *labelOpnd = &insn.GetOperand(kInsnSeventhOpnd);
1424 /* label: */
1425 labelOpnd->Accept(visitor);
1426 (void)emitter.Emit(":\n");
1427 Operand *retVal = &insn.GetOperand(kInsnFirstOpnd);
1428 /* ldaxr w0, [xt] */
1429 (void)emitter.Emit("\tldaxr\t");
1430 retVal->Accept(visitor);
1431 (void)emitter.Emit(", [");
1432 tempOpnd0->Accept(visitor);
1433 (void)emitter.Emit("]\n");
1434 Operand *newValueOpnd = &insn.GetOperand(kInsnSixthOpnd);
1435 /* stlxr ws, w3, [xt] */
1436 (void)emitter.Emit("\tstlxr\t");
1437 tempOpnd1->Accept(visitor);
1438 (void)emitter.Emit(", ");
1439 newValueOpnd->Accept(visitor);
1440 (void)emitter.Emit(", [");
1441 tempOpnd0->Accept(visitor);
1442 (void)emitter.Emit("]\n");
1443 /* cbnz w2, label */
1444 (void)emitter.Emit("\tcbnz\t");
1445 tempOpnd1->Accept(visitor);
1446 (void)emitter.Emit(", ");
1447 labelOpnd->Accept(visitor);
1448 (void)emitter.Emit("\n");
1449 }
1450
1451 /*
1452 * intrinsic_string_indexof w0, x1, w2, x3, w4, x5, x6, x7, x8, x9, w10,
1453 * Label.FIRST_LOOP, Label.STR2_NEXT, Label.STR1_LOOP,
1454 * Label.STR1_NEXT, Label.LAST_WORD, Label.NOMATCH, Label.RET
1455 * cmp w4, w2
1456 * b.gt .Label.NOMATCH
1457 * sub w2, w2, w4
1458 * sub w4, w4, #8
1459 * mov w10, w2
1460 * uxtw x4, w4
1461 * uxtw x2, w2
1462 * add x3, x3, x4
1463 * add x1, x1, x2
1464 * neg x4, x4
1465 * neg x2, x2
1466 * ldr x5, [x3,x4]
1467 * .Label.FIRST_LOOP:
1468 * ldr x7, [x1,x2]
1469 * cmp x5, x7
1470 * b.eq .Label.STR1_LOOP
1471 * .Label.STR2_NEXT:
1472 * adds x2, x2, #1
1473 * b.le .Label.FIRST_LOOP
1474 * b .Label.NOMATCH
1475 * .Label.STR1_LOOP:
1476 * adds x8, x4, #8
1477 * add x9, x2, #8
1478 * b.ge .Label.LAST_WORD
1479 * .Label.STR1_NEXT:
1480 * ldr x6, [x3,x8]
1481 * ldr x7, [x1,x9]
1482 * cmp x6, x7
1483 * b.ne .Label.STR2_NEXT
1484 * adds x8, x8, #8
1485 * add x9, x9, #8
1486 * b.lt .Label.STR1_NEXT
1487 * .Label.LAST_WORD:
1488 * ldr x6, [x3]
1489 * sub x9, x1, x4
1490 * ldr x7, [x9,x2]
1491 * cmp x6, x7
1492 * b.ne .Label.STR2_NEXT
1493 * add w0, w10, w2
1494 * b .Label.RET
1495 * .Label.NOMATCH:
1496 * mov w0, #-1
1497 * .Label.RET:
1498 */
EmitStringIndexOf(Emitter & emitter,const Insn & insn) const1499 void AArch64AsmEmitter::EmitStringIndexOf(Emitter &emitter, const Insn &insn) const
1500 {
1501 /* MOP_string_indexof has 18 operands */
1502 DEBUG_ASSERT(insn.GetOperandSize() == 18, "ensure the operands number");
1503 Operand *patternLengthOpnd = &insn.GetOperand(kInsnFifthOpnd);
1504 Operand *srcLengthOpnd = &insn.GetOperand(kInsnThirdOpnd);
1505 const std::string patternLengthReg =
1506 AArch64CG::intRegNames[AArch64CG::kR64List][static_cast<RegOperand *>(patternLengthOpnd)->GetRegisterNumber()];
1507 const std::string srcLengthReg =
1508 AArch64CG::intRegNames[AArch64CG::kR64List][static_cast<RegOperand *>(srcLengthOpnd)->GetRegisterNumber()];
1509 A64OpndEmitVisitor visitor(emitter, nullptr);
1510 /* cmp w4, w2 */
1511 (void)emitter.Emit("\tcmp\t");
1512 patternLengthOpnd->Accept(visitor);
1513 (void)emitter.Emit(", ");
1514 srcLengthOpnd->Accept(visitor);
1515 (void)emitter.Emit("\n");
1516 /* the 16th operand of MOP_string_indexof is Label.NOMATCH */
1517 Operand *labelNoMatch = &insn.GetOperand(16);
1518 /* b.gt Label.NOMATCH */
1519 (void)emitter.Emit("\tb.gt\t");
1520 labelNoMatch->Accept(visitor);
1521 (void)emitter.Emit("\n");
1522 /* sub w2, w2, w4 */
1523 (void)emitter.Emit("\tsub\t");
1524 srcLengthOpnd->Accept(visitor);
1525 (void)emitter.Emit(", ");
1526 srcLengthOpnd->Accept(visitor);
1527 (void)emitter.Emit(", ");
1528 patternLengthOpnd->Accept(visitor);
1529 (void)emitter.Emit("\n");
1530 /* sub w4, w4, #8 */
1531 (void)emitter.Emit("\tsub\t");
1532 patternLengthOpnd->Accept(visitor);
1533 (void)emitter.Emit(", ");
1534 patternLengthOpnd->Accept(visitor);
1535 (void)emitter.Emit(", #8\n");
1536 /* the 10th operand of MOP_string_indexof is w10 */
1537 Operand *resultTmp = &insn.GetOperand(10);
1538 /* mov w10, w2 */
1539 (void)emitter.Emit("\tmov\t");
1540 resultTmp->Accept(visitor);
1541 (void)emitter.Emit(", ");
1542 srcLengthOpnd->Accept(visitor);
1543 (void)emitter.Emit("\n");
1544 /* uxtw x4, w4 */
1545 (void)emitter.Emit("\tuxtw\t").Emit(patternLengthReg);
1546 (void)emitter.Emit(", ");
1547 patternLengthOpnd->Accept(visitor);
1548 (void)emitter.Emit("\n");
1549 /* uxtw x2, w2 */
1550 (void)emitter.Emit("\tuxtw\t").Emit(srcLengthReg);
1551 (void)emitter.Emit(", ");
1552 srcLengthOpnd->Accept(visitor);
1553 (void)emitter.Emit("\n");
1554 Operand *patternStringBaseOpnd = &insn.GetOperand(kInsnFourthOpnd);
1555 /* add x3, x3, x4 */
1556 (void)emitter.Emit("\tadd\t");
1557 patternStringBaseOpnd->Accept(visitor);
1558 (void)emitter.Emit(", ");
1559 patternStringBaseOpnd->Accept(visitor);
1560 (void)emitter.Emit(", ").Emit(patternLengthReg);
1561 (void)emitter.Emit("\n");
1562 Operand *srcStringBaseOpnd = &insn.GetOperand(kInsnSecondOpnd);
1563 /* add x1, x1, x2 */
1564 (void)emitter.Emit("\tadd\t");
1565 srcStringBaseOpnd->Accept(visitor);
1566 (void)emitter.Emit(", ");
1567 srcStringBaseOpnd->Accept(visitor);
1568 (void)emitter.Emit(", ").Emit(srcLengthReg);
1569 (void)emitter.Emit("\n");
1570 /* neg x4, x4 */
1571 (void)emitter.Emit("\tneg\t").Emit(patternLengthReg);
1572 (void)emitter.Emit(", ").Emit(patternLengthReg);
1573 (void)emitter.Emit("\n");
1574 /* neg x2, x2 */
1575 (void)emitter.Emit("\tneg\t").Emit(srcLengthReg);
1576 (void)emitter.Emit(", ").Emit(srcLengthReg);
1577 (void)emitter.Emit("\n");
1578 Operand *first = &insn.GetOperand(kInsnSixthOpnd);
1579 /* ldr x5, [x3,x4] */
1580 (void)emitter.Emit("\tldr\t");
1581 first->Accept(visitor);
1582 (void)emitter.Emit(", [");
1583 patternStringBaseOpnd->Accept(visitor);
1584 (void)emitter.Emit(",").Emit(patternLengthReg);
1585 (void)emitter.Emit("]\n");
1586 /* the 11th operand of MOP_string_indexof is Label.FIRST_LOOP */
1587 Operand *labelFirstLoop = &insn.GetOperand(11);
1588 /* .Label.FIRST_LOOP: */
1589 labelFirstLoop->Accept(visitor);
1590 (void)emitter.Emit(":\n");
1591 /* the 7th operand of MOP_string_indexof is x7 */
1592 Operand *ch2 = &insn.GetOperand(7);
1593 /* ldr x7, [x1,x2] */
1594 (void)emitter.Emit("\tldr\t");
1595 ch2->Accept(visitor);
1596 (void)emitter.Emit(", [");
1597 srcStringBaseOpnd->Accept(visitor);
1598 (void)emitter.Emit(",").Emit(srcLengthReg);
1599 (void)emitter.Emit("]\n");
1600 /* cmp x5, x7 */
1601 (void)emitter.Emit("\tcmp\t");
1602 first->Accept(visitor);
1603 (void)emitter.Emit(", ");
1604 ch2->Accept(visitor);
1605 (void)emitter.Emit("\n");
1606 /* the 13th operand of MOP_string_indexof is Label.STR1_LOOP */
1607 Operand *labelStr1Loop = &insn.GetOperand(13);
1608 /* b.eq .Label.STR1_LOOP */
1609 (void)emitter.Emit("\tb.eq\t");
1610 labelStr1Loop->Accept(visitor);
1611 (void)emitter.Emit("\n");
1612 /* the 12th operand of MOP_string_indexof is Label.STR2_NEXT */
1613 Operand *labelStr2Next = &insn.GetOperand(12);
1614 /* .Label.STR2_NEXT: */
1615 labelStr2Next->Accept(visitor);
1616 (void)emitter.Emit(":\n");
1617 /* adds x2, x2, #1 */
1618 (void)emitter.Emit("\tadds\t").Emit(srcLengthReg);
1619 (void)emitter.Emit(", ").Emit(srcLengthReg);
1620 (void)emitter.Emit(", #1\n");
1621 /* b.le .Label.FIRST_LOOP */
1622 (void)emitter.Emit("\tb.le\t");
1623 labelFirstLoop->Accept(visitor);
1624 (void)emitter.Emit("\n");
1625 /* b .Label.NOMATCH */
1626 (void)emitter.Emit("\tb\t");
1627 labelNoMatch->Accept(visitor);
1628 (void)emitter.Emit("\n");
1629 /* .Label.STR1_LOOP: */
1630 labelStr1Loop->Accept(visitor);
1631 (void)emitter.Emit(":\n");
1632 /* the 8th operand of MOP_string_indexof is x8 */
1633 Operand *tmp1 = &insn.GetOperand(kInsnEighthOpnd);
1634 /* adds x8, x4, #8 */
1635 (void)emitter.Emit("\tadds\t");
1636 tmp1->Accept(visitor);
1637 (void)emitter.Emit(", ").Emit(patternLengthReg);
1638 (void)emitter.Emit(", #8\n");
1639 /* the 9th operand of MOP_string_indexof is x9 */
1640 Operand *tmp2 = &insn.GetOperand(9);
1641 /* add x9, x2, #8 */
1642 (void)emitter.Emit("\tadd\t");
1643 tmp2->Accept(visitor);
1644 (void)emitter.Emit(", ").Emit(srcLengthReg);
1645 (void)emitter.Emit(", #8\n");
1646 /* the 15th operand of MOP_string_indexof is Label.LAST_WORD */
1647 Operand *labelLastWord = &insn.GetOperand(15);
1648 /* b.ge .Label.LAST_WORD */
1649 (void)emitter.Emit("\tb.ge\t");
1650 labelLastWord->Accept(visitor);
1651 (void)emitter.Emit("\n");
1652 /* the 14th operand of MOP_string_indexof is Label.STR1_NEXT */
1653 Operand *labelStr1Next = &insn.GetOperand(14);
1654 /* .Label.STR1_NEXT: */
1655 labelStr1Next->Accept(visitor);
1656 (void)emitter.Emit(":\n");
1657 /* the 6th operand of MOP_string_indexof is x6 */
1658 Operand *ch1 = &insn.GetOperand(6);
1659 /* ldr x6, [x3,x8] */
1660 (void)emitter.Emit("\tldr\t");
1661 ch1->Accept(visitor);
1662 (void)emitter.Emit(", [");
1663 patternStringBaseOpnd->Accept(visitor);
1664 (void)emitter.Emit(",");
1665 tmp1->Accept(visitor);
1666 (void)emitter.Emit("]\n");
1667 /* ldr x7, [x1,x9] */
1668 (void)emitter.Emit("\tldr\t");
1669 ch2->Accept(visitor);
1670 (void)emitter.Emit(", [");
1671 srcStringBaseOpnd->Accept(visitor);
1672 (void)emitter.Emit(",");
1673 tmp2->Accept(visitor);
1674 (void)emitter.Emit("]\n");
1675 /* cmp x6, x7 */
1676 (void)emitter.Emit("\tcmp\t");
1677 ch1->Accept(visitor);
1678 (void)emitter.Emit(", ");
1679 ch2->Accept(visitor);
1680 (void)emitter.Emit("\n");
1681 /* b.ne .Label.STR2_NEXT */
1682 (void)emitter.Emit("\tb.ne\t");
1683 labelStr2Next->Accept(visitor);
1684 (void)emitter.Emit("\n");
1685 /* adds x8, x8, #8 */
1686 (void)emitter.Emit("\tadds\t");
1687 tmp1->Accept(visitor);
1688 (void)emitter.Emit(", ");
1689 tmp1->Accept(visitor);
1690 (void)emitter.Emit(", #8\n");
1691 /* add x9, x9, #8 */
1692 (void)emitter.Emit("\tadd\t");
1693 tmp2->Accept(visitor);
1694 (void)emitter.Emit(", ");
1695 tmp2->Accept(visitor);
1696 (void)emitter.Emit(", #8\n");
1697 /* b.lt .Label.STR1_NEXT */
1698 (void)emitter.Emit("\tb.lt\t");
1699 labelStr1Next->Accept(visitor);
1700 (void)emitter.Emit("\n");
1701 /* .Label.LAST_WORD: */
1702 labelLastWord->Accept(visitor);
1703 (void)emitter.Emit(":\n");
1704 /* ldr x6, [x3] */
1705 (void)emitter.Emit("\tldr\t");
1706 ch1->Accept(visitor);
1707 (void)emitter.Emit(", [");
1708 patternStringBaseOpnd->Accept(visitor);
1709 (void)emitter.Emit("]\n");
1710 /* sub x9, x1, x4 */
1711 (void)emitter.Emit("\tsub\t");
1712 tmp2->Accept(visitor);
1713 (void)emitter.Emit(", ");
1714 srcStringBaseOpnd->Accept(visitor);
1715 (void)emitter.Emit(", ").Emit(patternLengthReg);
1716 (void)emitter.Emit("\n");
1717 /* ldr x7, [x9,x2] */
1718 (void)emitter.Emit("\tldr\t");
1719 ch2->Accept(visitor);
1720 (void)emitter.Emit(", [");
1721 tmp2->Accept(visitor);
1722 (void)emitter.Emit(", ").Emit(srcLengthReg);
1723 (void)emitter.Emit("]\n");
1724 /* cmp x6, x7 */
1725 (void)emitter.Emit("\tcmp\t");
1726 ch1->Accept(visitor);
1727 (void)emitter.Emit(", ");
1728 ch2->Accept(visitor);
1729 (void)emitter.Emit("\n");
1730 /* b.ne .Label.STR2_NEXT */
1731 (void)emitter.Emit("\tb.ne\t");
1732 labelStr2Next->Accept(visitor);
1733 (void)emitter.Emit("\n");
1734 Operand *retVal = &insn.GetOperand(kInsnFirstOpnd);
1735 /* add w0, w10, w2 */
1736 (void)emitter.Emit("\tadd\t");
1737 retVal->Accept(visitor);
1738 (void)emitter.Emit(", ");
1739 resultTmp->Accept(visitor);
1740 (void)emitter.Emit(", ");
1741 srcLengthOpnd->Accept(visitor);
1742 (void)emitter.Emit("\n");
1743 /* the 17th operand of MOP_string_indexof Label.ret */
1744 Operand *labelRet = &insn.GetOperand(17);
1745 /* b .Label.ret */
1746 (void)emitter.Emit("\tb\t");
1747 labelRet->Accept(visitor);
1748 (void)emitter.Emit("\n");
1749 /* .Label.NOMATCH: */
1750 labelNoMatch->Accept(visitor);
1751 (void)emitter.Emit(":\n");
1752 /* mov w0, #-1 */
1753 (void)emitter.Emit("\tmov\t");
1754 retVal->Accept(visitor);
1755 (void)emitter.Emit(", #-1\n");
1756 /* .Label.ret: */
1757 labelRet->Accept(visitor);
1758 (void)emitter.Emit(":\n");
1759 }
1760
1761 /*
1762 * intrinsic_compare_swap_int x0, xt, xs, x1, x2, w3, w4, lable1, label2
1763 * add xt, x1, x2
1764 * label1:
1765 * ldaxr ws, [xt]
1766 * cmp ws, w3
1767 * b.ne label2
1768 * stlxr ws, w4, [xt]
1769 * cbnz ws, label1
1770 * label2:
1771 * cset x0, eq
1772 */
EmitCompareAndSwapInt(Emitter & emitter,const Insn & insn) const1773 void AArch64AsmEmitter::EmitCompareAndSwapInt(Emitter &emitter, const Insn &insn) const
1774 {
1775 /* MOP_compare_and_swapI and MOP_compare_and_swapL have 8 operands */
1776 DEBUG_ASSERT(insn.GetOperandSize() > kInsnEighthOpnd, "ensure the operands number");
1777 const MOperator mOp = insn.GetMachineOpcode();
1778 const InsnDesc *md = &AArch64CG::kMd[mOp];
1779 Operand *temp0 = &insn.GetOperand(kInsnSecondOpnd);
1780 Operand *temp1 = &insn.GetOperand(kInsnThirdOpnd);
1781 Operand *obj = &insn.GetOperand(kInsnFourthOpnd);
1782 Operand *offset = &insn.GetOperand(kInsnFifthOpnd);
1783 A64OpndEmitVisitor visitor(emitter, nullptr);
1784 /* add xt, x1, x2 */
1785 (void)emitter.Emit("\tadd\t");
1786 temp0->Accept(visitor);
1787 (void)emitter.Emit(", ");
1788 obj->Accept(visitor);
1789 (void)emitter.Emit(", ");
1790 offset->Accept(visitor);
1791 (void)emitter.Emit("\n");
1792 Operand *label1 = &insn.GetOperand(kInsnEighthOpnd);
1793 /* label1: */
1794 label1->Accept(visitor);
1795 (void)emitter.Emit(":\n");
1796 /* ldaxr ws, [xt] */
1797 (void)emitter.Emit("\tldaxr\t");
1798 temp1->Accept(visitor);
1799 (void)emitter.Emit(", [");
1800 temp0->Accept(visitor);
1801 (void)emitter.Emit("]\n");
1802 Operand *expectedValue = &insn.GetOperand(kInsnSixthOpnd);
1803 const OpndDesc *expectedValueProp = md->opndMD[kInsnSixthOpnd];
1804 /* cmp ws, w3 */
1805 (void)emitter.Emit("\tcmp\t");
1806 temp1->Accept(visitor);
1807 (void)emitter.Emit(", ");
1808 A64OpndEmitVisitor visitorExpect(emitter, expectedValueProp);
1809 expectedValue->Accept(visitorExpect);
1810 (void)emitter.Emit("\n");
1811 constexpr uint32 kInsnNinethOpnd = 8;
1812 Operand *label2 = &insn.GetOperand(kInsnNinethOpnd);
1813 /* b.ne label2 */
1814 (void)emitter.Emit("\tbne\t");
1815 label2->Accept(visitor);
1816 (void)emitter.Emit("\n");
1817 Operand *newValue = &insn.GetOperand(kInsnSeventhOpnd);
1818 /* stlxr ws, w4, [xt] */
1819 (void)emitter.Emit("\tstlxr\t");
1820 (void)emitter.Emit(
1821 AArch64CG::intRegNames[AArch64CG::kR32List][static_cast<RegOperand *>(temp1)->GetRegisterNumber()]);
1822 (void)emitter.Emit(", ");
1823 newValue->Accept(visitor);
1824 (void)emitter.Emit(", [");
1825 temp0->Accept(visitor);
1826 (void)emitter.Emit("]\n");
1827 /* cbnz ws, label1 */
1828 (void)emitter.Emit("\tcbnz\t");
1829 (void)emitter.Emit(
1830 AArch64CG::intRegNames[AArch64CG::kR32List][static_cast<RegOperand *>(temp1)->GetRegisterNumber()]);
1831 (void)emitter.Emit(", ");
1832 label1->Accept(visitor);
1833 (void)emitter.Emit("\n");
1834 /* label2: */
1835 label2->Accept(visitor);
1836 (void)emitter.Emit(":\n");
1837 Operand *retVal = &insn.GetOperand(kInsnFirstOpnd);
1838 /* cset x0, eq */
1839 (void)emitter.Emit("\tcset\t");
1840 retVal->Accept(visitor);
1841 (void)emitter.Emit(", EQ\n");
1842 }
1843
EmitCTlsDescRel(Emitter & emitter,const Insn & insn) const1844 void AArch64AsmEmitter::EmitCTlsDescRel(Emitter &emitter, const Insn &insn) const
1845 {
1846 const InsnDesc *md = &AArch64CG::kMd[MOP_tls_desc_rel];
1847 Operand *result = &insn.GetOperand(kInsnFirstOpnd);
1848 Operand *src = &insn.GetOperand(kInsnSecondOpnd);
1849 Operand *symbol = &insn.GetOperand(kInsnThirdOpnd);
1850 auto stImmOpnd = static_cast<StImmOperand *>(symbol);
1851 A64OpndEmitVisitor resultVisitor(emitter, md->opndMD[0]);
1852 A64OpndEmitVisitor srcVisitor(emitter, md->opndMD[1]);
1853 (void)emitter.Emit("\t").Emit("add").Emit("\t");
1854 result->Accept(resultVisitor);
1855 (void)emitter.Emit(", ");
1856 src->Accept(srcVisitor);
1857 (void)emitter.Emit(", #:tprel_hi12:").Emit(stImmOpnd->GetName()).Emit(", lsl #12\n");
1858 (void)emitter.Emit("\t").Emit("add").Emit("\t");
1859 result->Accept(resultVisitor);
1860 (void)emitter.Emit(", ");
1861 result->Accept(resultVisitor);
1862 (void)emitter.Emit(", #:tprel_lo12_nc:").Emit(stImmOpnd->GetName()).Emit("\n");
1863 }
1864
EmitCTlsDescCall(Emitter & emitter,const Insn & insn) const1865 void AArch64AsmEmitter::EmitCTlsDescCall(Emitter &emitter, const Insn &insn) const
1866 {
1867 const InsnDesc *md = &AArch64CG::kMd[MOP_tls_desc_call];
1868 Operand *func = &insn.GetOperand(kInsnFirstOpnd);
1869 Operand *symbol = &insn.GetOperand(kInsnThirdOpnd);
1870 const OpndDesc *prop = md->opndMD[0];
1871 auto *stImmOpnd = static_cast<StImmOperand *>(symbol);
1872 const std::string &symName = stImmOpnd->GetName();
1873 A64OpndEmitVisitor funcVisitor(emitter, prop);
1874 /* adrp x0, :tlsdesc:symbol */
1875 (void)emitter.Emit("\t").Emit("adrp\tx0, :tlsdesc:").Emit(symName).Emit("\n");
1876 /* ldr x1, [x0, #tlsdesc_lo12:symbol] */
1877 (void)emitter.Emit("\t").Emit("ldr").Emit("\t");
1878 func->Accept(funcVisitor);
1879 (void)emitter.Emit(", [x0, #:tlsdesc_lo12:").Emit(symName).Emit("]\n");
1880 /* add x0 ,#tlsdesc_lo12:symbol */
1881 (void)emitter.Emit("\t").Emit("add\tx0, x0, :tlsdesc_lo12:").Emit(symName).Emit("\n");
1882 /* .tlsdesccall <symbolName> */
1883 (void)emitter.Emit("\t").Emit(".tlsdesccall").Emit("\t").Emit(symName).Emit("\n");
1884 /* blr xd */
1885 (void)emitter.Emit("\t").Emit("blr").Emit("\t");
1886 func->Accept(funcVisitor);
1887 (void)emitter.Emit("\n");
1888 }
1889
EmitSyncLockTestSet(Emitter & emitter,const Insn & insn) const1890 void AArch64AsmEmitter::EmitSyncLockTestSet(Emitter &emitter, const Insn &insn) const
1891 {
1892 const InsnDesc *md = &AArch64CG::kMd[insn.GetMachineOpcode()];
1893 auto *result = &insn.GetOperand(kInsnFirstOpnd);
1894 auto *temp = &insn.GetOperand(kInsnSecondOpnd);
1895 auto *addr = &insn.GetOperand(kInsnThirdOpnd);
1896 auto *value = &insn.GetOperand(kInsnFourthOpnd);
1897 auto *label = &insn.GetOperand(kInsnFifthOpnd);
1898 A64OpndEmitVisitor resultVisitor(emitter, md->opndMD[kInsnFirstOpnd]);
1899 A64OpndEmitVisitor tempVisitor(emitter, md->opndMD[kInsnSecondOpnd]);
1900 A64OpndEmitVisitor addrVisitor(emitter, md->opndMD[kInsnThirdOpnd]);
1901 A64OpndEmitVisitor valueVisitor(emitter, md->opndMD[kInsnFourthOpnd]);
1902 A64OpndEmitVisitor labelVisitor(emitter, md->opndMD[kInsnFifthOpnd]);
1903 /* label: */
1904 label->Accept(labelVisitor);
1905 (void)emitter.Emit(":\n");
1906 /* ldxr x0, [x2] */
1907 (void)emitter.Emit("\t").Emit("ldxr").Emit("\t");
1908 result->Accept(resultVisitor);
1909 (void)emitter.Emit(", [");
1910 addr->Accept(addrVisitor);
1911 (void)emitter.Emit("]\n");
1912 /* stxr w1, x3, [x2] */
1913 (void)emitter.Emit("\t").Emit("stxr").Emit("\t");
1914 temp->Accept(tempVisitor);
1915 (void)emitter.Emit(", ");
1916 value->Accept(valueVisitor);
1917 (void)emitter.Emit(", [");
1918 addr->Accept(addrVisitor);
1919 (void)emitter.Emit("]\n");
1920 /* cbnz w1, label */
1921 (void)emitter.Emit("\t").Emit("cbnz").Emit("\t");
1922 temp->Accept(tempVisitor);
1923 (void)emitter.Emit(", ");
1924 label->Accept(labelVisitor);
1925 (void)emitter.Emit("\n");
1926 /* dmb ish */
1927 (void)emitter.Emit("\t").Emit("dmb").Emit("\t").Emit("ish").Emit("\n");
1928 }
1929
EmitCheckThrowPendingException(Emitter & emitter,Insn & insn) const1930 void AArch64AsmEmitter::EmitCheckThrowPendingException(Emitter &emitter, Insn &insn) const
1931 {
1932 /*
1933 * mrs x16, TPIDR_EL0
1934 * ldr x16, [x16, #64]
1935 * ldr x16, [x16, #8]
1936 * cbz x16, .lnoexception
1937 * bl MCC_ThrowPendingException
1938 * .lnoexception:
1939 */
1940 (void)emitter.Emit("\t").Emit("mrs").Emit("\tx16, TPIDR_EL0");
1941 (void)emitter.Emit("\n");
1942 (void)emitter.Emit("\t").Emit("ldr").Emit("\tx16, [x16, #64]");
1943 (void)emitter.Emit("\n");
1944 (void)emitter.Emit("\t").Emit("ldr").Emit("\tx16, [x16, #8]");
1945 (void)emitter.Emit("\n");
1946 (void)emitter.Emit("\t").Emit("cbz").Emit("\tx16, .lnoeh.").Emit(maplebe::CG::GetCurCGFunc()->GetName());
1947 (void)emitter.Emit("\n");
1948 (void)emitter.Emit("\t").Emit("bl").Emit("\tMCC_ThrowPendingException");
1949 (void)emitter.Emit("\n");
1950 (void)emitter.Emit(".lnoeh.").Emit(maplebe::CG::GetCurCGFunc()->GetName()).Emit(":");
1951 (void)emitter.Emit("\n");
1952 }
1953
EmitLazyBindingRoutine(Emitter & emitter,const Insn & insn) const1954 void AArch64AsmEmitter::EmitLazyBindingRoutine(Emitter &emitter, const Insn &insn) const
1955 {
1956 /* ldr xzr, [xs] */
1957 const InsnDesc *md = &AArch64CG::kMd[MOP_adrp_ldr];
1958
1959 Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
1960 const OpndDesc *prop0 = md->opndMD[0];
1961 A64OpndEmitVisitor visitor(emitter, prop0);
1962
1963 /* emit "ldr xzr,[xs]" */
1964 #ifdef USE_32BIT_REF
1965 (void)emitter.Emit("\t").Emit("ldr").Emit("\twzr, [");
1966 #else
1967 (void)emitter.Emit("\t").Emit("ldr").Emit("\txzr, [");
1968 #endif /* USE_32BIT_REF */
1969 opnd0->Accept(visitor);
1970 (void)emitter.Emit("]");
1971 (void)emitter.Emit("\t// Lazy binding\n");
1972 }
1973
PrepareVectorOperand(RegOperand * regOpnd,uint32 & compositeOpnds,Insn & insn) const1974 void AArch64AsmEmitter::PrepareVectorOperand(RegOperand *regOpnd, uint32 &compositeOpnds, Insn &insn) const
1975 {
1976 VectorRegSpec *vecSpec = static_cast<VectorInsn &>(insn).GetAndRemoveRegSpecFromList();
1977 compositeOpnds = vecSpec->compositeOpnds ? vecSpec->compositeOpnds : compositeOpnds;
1978 regOpnd->SetVecLanePosition(vecSpec->vecLane);
1979 switch (insn.GetMachineOpcode()) {
1980 case MOP_vanduuu:
1981 case MOP_vxoruuu:
1982 case MOP_voruuu:
1983 case MOP_vnotuu:
1984 case MOP_vextuuui: {
1985 regOpnd->SetVecLaneSize(k8ByteSize);
1986 regOpnd->SetVecElementSize(k8BitSize);
1987 break;
1988 }
1989 case MOP_vandvvv:
1990 case MOP_vxorvvv:
1991 case MOP_vorvvv:
1992 case MOP_vnotvv:
1993 case MOP_vextvvvi: {
1994 regOpnd->SetVecLaneSize(k16ByteSize);
1995 regOpnd->SetVecElementSize(k8BitSize);
1996 break;
1997 }
1998 default: {
1999 regOpnd->SetVecLaneSize(vecSpec->vecLaneMax);
2000 regOpnd->SetVecElementSize(vecSpec->vecElementSize);
2001 break;
2002 }
2003 }
2004 }
2005
2006 struct CfiDescr {
2007 const std::string name;
2008 uint32 opndCount;
2009 /* create 3 OperandType array to store cfi instruction's operand type */
2010 std::array<Operand::OperandType, 3> opndTypes;
2011 };
2012
2013 static CfiDescr cfiDescrTable[cfi::kOpCfiLast + 1] = {
2014 #define CFI_DEFINE(k, sub, n, o0, o1, o2) {".cfi_" #k, n, {Operand::kOpd##o0, Operand::kOpd##o1, Operand::kOpd##o2}},
2015 #define ARM_DIRECTIVES_DEFINE(k, sub, n, o0, o1, o2) \
2016 {"." #k, n, {Operand::kOpd##o0, Operand::kOpd##o1, Operand::kOpd##o2}},
2017 #include "cfi.def"
2018 #undef CFI_DEFINE
2019 #undef ARM_DIRECTIVES_DEFINE
2020 {".cfi_undef", 0, {Operand::kOpdUndef, Operand::kOpdUndef, Operand::kOpdUndef}}};
2021
EmitAArch64CfiInsn(Emitter & emitter,const Insn & insn) const2022 void AArch64AsmEmitter::EmitAArch64CfiInsn(Emitter &emitter, const Insn &insn) const
2023 {
2024 MOperator mOp = insn.GetMachineOpcode();
2025 CfiDescr &cfiDescr = cfiDescrTable[mOp];
2026 (void)emitter.Emit("\t").Emit(cfiDescr.name);
2027 for (uint32 i = 0; i < cfiDescr.opndCount; ++i) {
2028 (void)emitter.Emit(" ");
2029 Operand &curOperand = insn.GetOperand(i);
2030 cfi::CFIOpndEmitVisitor cfiOpndEmitVisitor(emitter);
2031 curOperand.Accept(cfiOpndEmitVisitor);
2032 if (i < (cfiDescr.opndCount - 1)) {
2033 (void)emitter.Emit(",");
2034 }
2035 }
2036 (void)emitter.Emit("\n");
2037 }
2038
2039 struct DbgDescr {
2040 const std::string name;
2041 uint32 opndCount;
2042 /* create 3 OperandType array to store dbg instruction's operand type */
2043 std::array<Operand::OperandType, 3> opndTypes;
2044 };
2045
2046 static DbgDescr dbgDescrTable[mpldbg::kOpDbgLast + 1] = {
2047 #define DBG_DEFINE(k, sub, n, o0, o1, o2) {#k, n, {Operand::kOpd##o0, Operand::kOpd##o1, Operand::kOpd##o2}},
2048 #include "dbg.def"
2049 #undef DBG_DEFINE
2050 {"undef", 0, {Operand::kOpdUndef, Operand::kOpdUndef, Operand::kOpdUndef}}};
2051
EmitAArch64DbgInsn(Emitter & emitter,const Insn & insn) const2052 void AArch64AsmEmitter::EmitAArch64DbgInsn(Emitter &emitter, const Insn &insn) const
2053 {
2054 MOperator mOp = insn.GetMachineOpcode();
2055 DbgDescr &dbgDescr = dbgDescrTable[mOp];
2056 (void)emitter.Emit("\t.").Emit(dbgDescr.name);
2057 for (uint32 i = 0; i < dbgDescr.opndCount; ++i) {
2058 (void)emitter.Emit(" ");
2059 Operand &curOperand = insn.GetOperand(i);
2060 mpldbg::DBGOpndEmitVisitor dbgOpndEmitVisitor(emitter);
2061 curOperand.Accept(dbgOpndEmitVisitor);
2062 }
2063 (void)emitter.Emit("\n");
2064 }
2065
CheckInsnRefField(const Insn & insn,size_t opndIndex) const2066 bool AArch64AsmEmitter::CheckInsnRefField(const Insn &insn, size_t opndIndex) const
2067 {
2068 if (insn.IsAccessRefField() && insn.AccessMem()) {
2069 Operand &opnd0 = insn.GetOperand(opndIndex);
2070 if (opnd0.IsRegister()) {
2071 static_cast<RegOperand &>(opnd0).SetRefField(true);
2072 return true;
2073 }
2074 }
2075 return false;
2076 }
2077
2078 /* new phase manager */
PhaseRun(maplebe::CGFunc & f)2079 bool CgEmission::PhaseRun(maplebe::CGFunc &f)
2080 {
2081 Emitter *emitter = f.GetCG()->GetEmitter();
2082 CHECK_NULL_FATAL(emitter);
2083 if (CGOptions::GetEmitFileType() == CGOptions::kAsm) {
2084 AsmFuncEmitInfo funcEmitInfo(f);
2085 emitter->EmitLocalVariable(f);
2086 static_cast<AArch64AsmEmitter *>(emitter)->Run(funcEmitInfo);
2087 emitter->EmitHugeSoRoutines();
2088 } else {
2089 FuncEmitInfo &funcEmitInfo = static_cast<AArch64ObjEmitter *>(emitter)->CreateFuncEmitInfo(f);
2090 static_cast<AArch64ObjEmitter *>(emitter)->Run(funcEmitInfo);
2091 f.SetFuncEmitInfo(&funcEmitInfo);
2092 }
2093
2094 return false;
2095 }
2096 MAPLE_TRANSFORM_PHASE_REGISTER(CgEmission, cgemit)
2097 } /* namespace maplebe */
2098