• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "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 #include "operand.h"
25 
26 namespace {
27 using namespace maple;
28 }  // namespace
29 
30 namespace maplebe {
31 using namespace maple;
32 
33 /* the fast_exception_handling lsda */
EmitFastLSDA(FuncEmitInfo & funcEmitInfo)34 void AArch64AsmEmitter::EmitFastLSDA(FuncEmitInfo &funcEmitInfo)
35 {
36     CGFunc &cgFunc = funcEmitInfo.GetCGFunc();
37     AArch64CGFunc &aarchCGFunc = static_cast<AArch64CGFunc &>(cgFunc);
38     CG *currCG = cgFunc.GetCG();
39 
40     PUIdx pIdx = currCG->GetMIRModule()->CurFunction()->GetPuidx();
41     char *idx = strdup(std::to_string(pIdx).c_str());
42     CHECK_FATAL(idx != nullptr, "strdup failed");
43     /*
44      * .word 0xFFFFFFFF
45      * .word .Label.LTest_3B_7C_3Cinit_3E_7C_28_29V3-func_start_label
46      */
47     currCG->template Emit<CG::EmitterType::AsmEmitter>([&cgFunc, &aarchCGFunc, idx](Emitter* emitter) {
48         (void)emitter->Emit("\t.word 0xFFFFFFFF\n");
49         (void)emitter->Emit("\t.word .L.").Emit(idx).Emit("__");
50         if (aarchCGFunc.NeedCleanup()) {
51             emitter->Emit(cgFunc.GetCleanupLabel()->GetLabelIdx());
52         } else {
53             DEBUG_ASSERT(!cgFunc.GetExitBBsVec().empty(), "exitbbsvec is empty in AArch64AsmEmitter::EmitFastLSDA");
54             emitter->Emit(cgFunc.GetExitBB(0)->GetLabIdx());
55         }
56         emitter->Emit("-.L.").Emit(idx).Emit("__").Emit(cgFunc.GetStartLabel()->GetLabelIdx()).Emit("\n");
57     });
58     free(idx);
59     idx = nullptr;
60 }
61 
EmitBBHeaderLabel(FuncEmitInfo & funcEmitInfo,const std::string & name,LabelIdx labIdx)62 void AArch64AsmEmitter::EmitBBHeaderLabel(FuncEmitInfo &funcEmitInfo, const std::string &name, LabelIdx labIdx)
63 {
64     (void)name;
65     CGFunc &cgFunc = funcEmitInfo.GetCGFunc();
66     AArch64CGFunc &aarchCGFunc = static_cast<AArch64CGFunc &>(cgFunc);
67     CG *currCG = cgFunc.GetCG();
68     LabelOperand &label = aarchCGFunc.GetOrCreateLabelOperand(labIdx);
69     /* if label order is default value -1, set new order */
70     if (label.GetLabelOrder() == 0xFFFFFFFF) {
71         label.SetLabelOrder(currCG->GetLabelOrderCnt());
72         currCG->IncreaseLabelOrderCnt();
73     }
74     CHECK_NULL_FATAL(currCG->GetMIRModule()->CurFunction());
75     PUIdx pIdx = currCG->GetMIRModule()->CurFunction()->GetPuidx();
76     char *puIdx = strdup(std::to_string(pIdx).c_str());
77     CHECK_FATAL(puIdx != nullptr, "strdup failed");
78     currCG->template Emit<CG::EmitterType::AsmEmitter>([&cgFunc, currCG, puIdx, labIdx, label](Emitter* emitter) {
79         const std::string &labelName = cgFunc.GetFunction().GetLabelTab()->GetName(labIdx);
80         if (currCG->GenerateVerboseCG()) {
81             (void)emitter->Emit(".L.")
82                 .Emit(puIdx)
83                 .Emit("__")
84                 .Emit(labIdx)
85                 .Emit(":\t//label order ")
86                 .Emit(label.GetLabelOrder());
87             if (!labelName.empty() && labelName.at(0) != '@') {
88                 /* If label name has @ as its first char, it is not from MIR */
89                 (void)emitter->Emit(", MIR: @").Emit(labelName).Emit("\n");
90             } else {
91                 (void)emitter->Emit("\n");
92             }
93         } else {
94             (void)emitter->Emit(".L.").Emit(puIdx).Emit("__").Emit(labIdx).Emit(":\n");
95         }
96     });
97     free(puIdx);
98     puIdx = nullptr;
99 }
100 
RecordRegInfo(FuncEmitInfo & funcEmitInfo) const101 void AArch64AsmEmitter::RecordRegInfo(FuncEmitInfo &funcEmitInfo) const
102 {
103     if (!CGOptions::DoIPARA()) {
104         return;
105     }
106     CGFunc &cgFunc = funcEmitInfo.GetCGFunc();
107     AArch64CGFunc &aarchCGFunc = static_cast<AArch64CGFunc &>(cgFunc);
108 
109     std::set<regno_t> referedRegs;
110     MIRFunction &mirFunc = cgFunc.GetFunction();
111     FOR_ALL_BB_REV(bb, &aarchCGFunc)
112     {
113         FOR_BB_INSNS_REV(insn, bb)
114         {
115             if (!insn->IsMachineInstruction()) {
116                 continue;
117             }
118             if (insn->IsCall() || insn->IsTailCall()) {
119                 auto *targetOpnd = insn->GetCallTargetOperand();
120                 bool safeCheck = false;
121                 CHECK_FATAL(targetOpnd != nullptr,
122                             "target is null in AArch64Emitter::IsCallToFunctionThatNeverReturns");
123                 if (targetOpnd->IsFuncNameOpnd()) {
124                     FuncNameOperand *target = static_cast<FuncNameOperand *>(targetOpnd);
125                     const MIRSymbol *funcSt = target->GetFunctionSymbol();
126                     DEBUG_ASSERT(funcSt->GetSKind() == maple::kStFunc, "funcst must be a function name symbol");
127                     MIRFunction *func = funcSt->GetFunction();
128                     if (func != nullptr && func->IsReferedRegsValid()) {
129                         safeCheck = true;
130                         for (auto preg : func->GetReferedRegs()) {
131                             referedRegs.insert(preg);
132                         }
133                     }
134                 }
135                 if (!safeCheck) {
136                     mirFunc.SetReferedRegsValid(false);
137                     return;
138                 }
139             }
140             if (referedRegs.size() == kMaxRegNum) {
141                 break;
142             }
143             uint32 opndNum = insn->GetOperandSize();
144             const InsnDesc *md = &AArch64CG::kMd[insn->GetMachineOpcode()];
145             for (uint32 i = 0; i < opndNum; ++i) {
146                 if (insn->GetMachineOpcode() == MOP_asm) {
147                     if (i == kAsmOutputListOpnd || i == kAsmClobberListOpnd) {
148                         for (auto opnd : static_cast<ListOperand &>(insn->GetOperand(i)).GetOperands()) {
149                             if (opnd->IsRegister()) {
150                                 referedRegs.insert(static_cast<RegOperand *>(opnd)->GetRegisterNumber());
151                             }
152                         }
153                     }
154                     continue;
155                 }
156                 Operand &opnd = insn->GetOperand(i);
157                 if (opnd.IsList()) {
158                     /* all use, skip it */
159                 } else if (opnd.IsMemoryAccessOperand()) {
160                     auto &memOpnd = static_cast<MemOperand &>(opnd);
161                     RegOperand *base = memOpnd.GetBaseRegister();
162                     if (!memOpnd.IsIntactIndexed()) {
163                         referedRegs.insert(base->GetRegisterNumber());
164                     }
165                 } else if (opnd.IsRegister()) {
166                     RegType regType = static_cast<RegOperand &>(opnd).GetRegisterType();
167                     if (regType == kRegTyCc || regType == kRegTyVary) {
168                         continue;
169                     }
170                     bool isDef = md->GetOpndDes(i)->IsRegDef();
171                     if (isDef) {
172                         referedRegs.insert(static_cast<RegOperand &>(opnd).GetRegisterNumber());
173                     }
174                 }
175             }
176         }
177     }
178     mirFunc.SetReferedRegsValid(true);
179 #ifdef DEBUG
180     for (auto reg : referedRegs) {
181         if (reg > kMaxRegNum) {
182             DEBUG_ASSERT(0, "unexpected preg");
183         }
184     }
185 #endif
186     mirFunc.CopyReferedRegs(referedRegs);
187 }
188 
Run(FuncEmitInfo & funcEmitInfo)189 void AArch64AsmEmitter::Run(FuncEmitInfo &funcEmitInfo)
190 {
191     CGFunc &cgFunc = funcEmitInfo.GetCGFunc();
192     AArch64CGFunc &aarchCGFunc = static_cast<AArch64CGFunc &>(cgFunc);
193     CG *currCG = cgFunc.GetCG();
194     /* emit header of this function */
195     currCG->template Emit<CG::EmitterType::AsmEmitter>(
196     [this, &cgFunc, &aarchCGFunc, currCG, &funcEmitInfo](Emitter *emitter) {
197         // insert for  __cxx_global_var_init
198         if (cgFunc.GetName() == "__cxx_global_var_init") {
199             (void)emitter->Emit("\t.section\t.init_array,\"aw\"\n");
200             (void)emitter->Emit("\t.quad\t").Emit(cgFunc.GetName()).Emit("\n");
201         }
202         if (cgFunc.GetFunction().GetAttr(FUNCATTR_initialization)) {
203             (void)emitter->Emit("\t.section\t.init_array,\"aw\"\n");
204             (void)emitter->Emit("\t.quad\t").Emit(cgFunc.GetName()).Emit("\n");
205         }
206         if (cgFunc.GetFunction().GetAttr(FUNCATTR_termination)) {
207             (void)emitter->Emit("\t.section\t.fini_array,\"aw\"\n");
208             (void)emitter->Emit("\t.quad\t").Emit(cgFunc.GetName()).Emit("\n");
209         }
210         (void)emitter->Emit("\n");
211         if (cgFunc.GetFunction().GetAttr(FUNCATTR_section)) {
212             const std::string &sectionName = cgFunc.GetFunction().GetAttrs().GetPrefixSectionName();
213             (void)emitter->Emit("\t.section  " + sectionName).Emit(",\"ax\",@progbits\n");
214         } else if (CGOptions::IsFunctionSections()) {
215             (void)emitter->Emit("\t.section  .text.").Emit(cgFunc.GetName()).Emit(",\"ax\",@progbits\n");
216         } else if (cgFunc.GetFunction().GetAttr(FUNCATTR_constructor_priority)) {
217             (void)emitter->Emit("\t.section\t.text.startup").Emit(",\"ax\",@progbits\n");
218         } else {
219             (void)emitter->Emit("\t.text\n");
220         }
221         if (CGOptions::GetFuncAlignPow() != 0) {
222             (void)emitter->Emit("\t.align ").Emit(CGOptions::GetFuncAlignPow()).Emit("\n");
223         }
224         MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStidx(cgFunc.GetFunction().GetStIdx().Idx());
225         const std::string &funcName = std::string(cgFunc.GetShortFuncName().c_str());
226 
227         std::string funcStName = funcSt->GetName();
228         if (funcSt->GetFunction()->GetAttr(FUNCATTR_weak)) {
229             (void)emitter->Emit("\t.weak\t" + funcStName + "\n");
230             (void)emitter->Emit("\t.hidden\t" + funcStName + "\n");
231         } else if (funcSt->GetFunction()->GetAttr(FUNCATTR_local)) {
232             (void)emitter->Emit("\t.local\t" + funcStName + "\n");
233         } else if (funcSt->GetFunction() && funcSt->GetFunction()->IsStatic()) {
234             // nothing
235         } else {
236             /* should refer to function attribute */
237             (void)emitter->Emit("\t.globl\t").Emit(funcSt->GetName()).Emit("\n");
238             if (!currCG->GetMIRModule()->IsCModule()) {
239                 (void)emitter->Emit("\t.hidden\t").Emit(funcSt->GetName()).Emit("\n");
240             }
241         }
242         (void)emitter->Emit("\t.type\t" + funcStName + ", %function\n");
243         (void)emitter->Emit(funcStName + ":\n");
244 
245         /* if the last  insn is call, then insert nop */
246         bool found = false;
247         FOR_ALL_BB_REV(bb, &aarchCGFunc)
248         {
249             FOR_BB_INSNS_REV(insn, bb)
250             {
251                 if (insn->IsMachineInstruction()) {
252                     if (insn->IsCall()) {
253                         Insn &newInsn = aarchCGFunc.GetInsnBuilder()->BuildInsn<AArch64CG>(MOP_nop);
254                         bb->InsertInsnAfter(*insn, newInsn);
255                     }
256                     found = true;
257                     break;
258                 }
259             }
260             if (found) {
261                 break;
262             }
263         }
264 
265         RecordRegInfo(funcEmitInfo);
266 
267         /* emit instructions */
268         FOR_ALL_BB(bb, &aarchCGFunc)
269         {
270             if (bb->IsUnreachable()) {
271                 continue;
272             }
273             if (currCG->GenerateVerboseCG()) {
274                 (void)emitter->Emit("#    freq:").Emit(bb->GetFrequency()).Emit("\n");
275             }
276             /* emit bb headers */
277             if (bb->GetLabIdx() != MIRLabelTable::GetDummyLabel()) {
278                 if (aarchCGFunc.GetMirModule().IsCModule() && bb->IsBBNeedAlign() &&
279                     bb->GetAlignNopNum() != kAlignMovedFlag) {
280                     uint32 power = bb->GetAlignPower();
281                     (void)emitter->Emit("\t.p2align ").Emit(power).Emit("\n");
282                 }
283                 EmitBBHeaderLabel(funcEmitInfo, funcName, bb->GetLabIdx());
284             }
285 
286             FOR_BB_INSNS(insn, bb)
287             {
288                 auto dbgComment = insn->GetDebugComment();
289                 if (currDebugComment != dbgComment) {
290                     currDebugComment = dbgComment;
291                     if (dbgComment != nullptr) {
292                         emitter->Emit("\t// ");
293                         emitter->Emit(dbgComment->c_str());
294                         emitter->Emit("\n ");
295                     } else {
296                         emitter->Emit("\t// \n");
297                     }
298                 }
299                 if (insn->IsCfiInsn()) {
300                     EmitAArch64CfiInsn(*emitter, *insn);
301                 } else if (insn->IsDbgInsn()) {
302                     EmitAArch64DbgInsn(*emitter, *insn);
303                 } else {
304                     EmitAArch64Insn(*emitter, *insn);
305                 }
306             }
307         }
308         if (CGOptions::IsMapleLinker()) {
309             /* Emit a label for calculating method size */
310             (void)emitter->Emit(".Label.end." + funcStName + ":\n");
311         }
312         (void)emitter->Emit("\t.size\t" + funcStName + ", .-").Emit(funcStName + "\n");
313 
314         auto constructorAttr = funcSt->GetFunction()->GetAttrs().GetConstructorPriority();
315         if (constructorAttr != -1) {
316             (void)emitter->Emit("\t.section\t.init_array." + std::to_string(constructorAttr) + ",\"aw\"\n");
317             (void)emitter->Emit("\t.align 3\n");
318             (void)emitter->Emit("\t.xword\t" + funcStName + "\n");
319         }
320 
321         EmitFunctionSymbolTable(funcEmitInfo);
322 
323         for (auto &it : cgFunc.GetEmitStVec()) {
324             /* emit switch table only here */
325             MIRSymbol *st = it.second;
326             DEBUG_ASSERT(st->IsReadOnly(), "NYI");
327             (void)emitter->Emit("\n");
328             (void)emitter->Emit("\t.align 3\n");
329             (void)emitter->Emit(st->GetName() + ":\n");
330             MIRAggConst *arrayConst = safe_cast<MIRAggConst>(st->GetKonst());
331             CHECK_FATAL(arrayConst != nullptr, "null ptr check");
332             PUIdx pIdx = cgFunc.GetMirModule().CurFunction()->GetPuidx();
333             char *idx = strdup(std::to_string(pIdx).c_str());
334             CHECK_FATAL(idx != nullptr, "strdup failed");
335             for (size_t i = 0; i < arrayConst->GetConstVec().size(); i++) {
336                 MIRLblConst *lblConst = safe_cast<MIRLblConst>(arrayConst->GetConstVecItem(i));
337                 CHECK_FATAL(lblConst != nullptr, "null ptr check");
338                 (void)emitter->Emit("\t.quad\t.L.").Emit(idx).Emit("__").Emit(lblConst->GetValue());
339                 (void)emitter->Emit(" - " + st->GetName() + "\n");
340             }
341             free(idx);
342             idx = nullptr;
343         }
344 
345         for (const auto &mpPair : cgFunc.GetLabelAndValueMap()) {
346             LabelOperand &labelOpnd = aarchCGFunc.GetOrCreateLabelOperand(mpPair.first);
347             A64OpndEmitVisitor visitor(*emitter, nullptr);
348             labelOpnd.Accept(visitor);
349             (void)emitter->Emit(":\n");
350             (void)emitter->Emit("\t.quad ").Emit(static_cast<int64>(mpPair.second)).Emit("\n");
351         }
352     });
353 }
354 
EmitAArch64Insn(maplebe::Emitter & emitter,Insn & insn) const355 void AArch64AsmEmitter::EmitAArch64Insn(maplebe::Emitter &emitter, Insn &insn) const
356 {
357     MOperator mOp = insn.GetMachineOpcode();
358     emitter.SetCurrentMOP(mOp);
359     const InsnDesc *md = insn.GetDesc();
360 
361     if (!GetCG()->GenerateVerboseAsm() && !GetCG()->GenerateVerboseCG() && insn.IsComment()) {
362         return;
363     }
364 
365     switch (mOp) {
366         case MOP_adrp_ldr: {
367             EmitAdrpLdr(emitter, insn);
368             if (CGOptions::IsLazyBinding() && !GetCG()->IsLibcore()) {
369                 EmitLazyBindingRoutine(emitter, insn);
370             }
371             return;
372         }
373         case MOP_counter: {
374             EmitCounter(emitter, insn);
375             return;
376         }
377         case MOP_asm: {
378             EmitInlineAsm(emitter, insn);
379             return;
380         }
381         case MOP_clinit_tail: {
382             EmitClinitTail(emitter, insn);
383             return;
384         }
385         case MOP_lazy_ldr: {
386             EmitLazyLoad(emitter, insn);
387             return;
388         }
389         case MOP_adrp_label: {
390             EmitAdrpLabel(emitter, insn);
391             return;
392         }
393         case MOP_lazy_tail: {
394             /* No need to emit this pseudo instruction. */
395             return;
396         }
397         case MOP_lazy_ldr_static: {
398             EmitLazyLoadStatic(emitter, insn);
399             return;
400         }
401         case MOP_arrayclass_cache_ldr: {
402             EmitArrayClassCacheLoad(emitter, insn);
403             return;
404         }
405         case MOP_get_and_addI:
406         case MOP_get_and_addL: {
407             EmitGetAndAddInt(emitter, insn);
408             return;
409         }
410         case MOP_get_and_setI:
411         case MOP_get_and_setL: {
412             EmitGetAndSetInt(emitter, insn);
413             return;
414         }
415         case MOP_compare_and_swapI:
416         case MOP_compare_and_swapL: {
417             EmitCompareAndSwapInt(emitter, insn);
418             return;
419         }
420         case MOP_string_indexof: {
421             EmitStringIndexOf(emitter, insn);
422             return;
423         }
424         case MOP_pseudo_none:
425         case MOP_pseduo_tls_release: {
426             return;
427         }
428         case MOP_tls_desc_call: {
429             EmitCTlsDescCall(emitter, insn);
430             return;
431         }
432         case MOP_tls_desc_rel: {
433             EmitCTlsDescRel(emitter, insn);
434             return;
435         }
436         case MOP_sync_lock_test_setI:
437         case MOP_sync_lock_test_setL: {
438             EmitSyncLockTestSet(emitter, insn);
439             return;
440         }
441         default:
442             break;
443     }
444 
445     if (CGOptions::IsNativeOpt() && mOp == MOP_xbl) {
446         auto *nameOpnd = static_cast<FuncNameOperand *>(&insn.GetOperand(kInsnFirstOpnd));
447         if (nameOpnd->GetName() == "MCC_CheckThrowPendingException") {
448             EmitCheckThrowPendingException(emitter, insn);
449             return;
450         }
451     }
452 
453     std::string format(md->format);
454     (void)emitter.Emit("\t").Emit(md->name).Emit("\t");
455     size_t opndSize = insn.GetOperandSize();
456     std::vector<int32> seq(opndSize, -1);
457     std::vector<std::string> prefix(opndSize); /* used for print prefix like "*" in icall *rax */
458     uint32 index = 0;
459     uint32 commaNum = 0;
460     for (uint32 i = 0; i < format.length(); ++i) {
461         char c = format[i];
462         if (c >= '0' && c <= '5') {
463             seq[index++] = c - '0';
464             ++commaNum;
465         } else if (c != ',') {
466             prefix[index].push_back(c);
467         }
468     }
469 
470     bool isRefField =
471         (opndSize == 0) ? false : CheckInsnRefField(insn, static_cast<size_t>(static_cast<uint32>(seq[0])));
472     uint32 compositeOpnds = 0;
473     for (uint32 i = 0; i < commaNum; ++i) {
474         if (seq[i] == -1) {
475             continue;
476         }
477         if (prefix[i].length() > 0) {
478             (void)emitter.Emit(prefix[i]);
479         }
480         if (emitter.NeedToDealWithHugeSo() && (mOp == MOP_xbl || mOp == MOP_tail_call_opt_xbl)) {
481             auto *nameOpnd = static_cast<FuncNameOperand *>(&insn.GetOperand(kInsnFirstOpnd));
482             emitter.InsertHugeSoTarget(nameOpnd->GetName());
483             (void)emitter.Emit(nameOpnd->GetName() + emitter.HugeSoPostFix());
484             break;
485         }
486         auto *opnd = &insn.GetOperand(static_cast<uint32>(seq[i]));
487         if (opnd && opnd->IsRegister()) {
488             auto *regOpnd = static_cast<RegOperand *>(opnd);
489             if ((md->opndMD[static_cast<uint32>(seq[i])])->IsVectorOperand()) {
490                 regOpnd->SetVecLanePosition(-1);
491                 regOpnd->SetVecLaneSize(0);
492                 regOpnd->SetVecElementSize(0);
493                 if (insn.IsVectorOp()) {
494                     PrepareVectorOperand(regOpnd, compositeOpnds, insn);
495                     if (compositeOpnds != 0) {
496                         (void)emitter.Emit("{");
497                     }
498                 }
499             }
500         }
501         A64OpndEmitVisitor visitor(emitter, md->opndMD[static_cast<uint32>(seq[i])]);
502 
503         insn.GetOperand(static_cast<uint32>(seq[i])).Accept(visitor);
504         if (compositeOpnds == 1) {
505             (void)emitter.Emit("}");
506         }
507         if (compositeOpnds > 0) {
508             --compositeOpnds;
509         }
510         /* reset opnd0 ref-field flag, so following instruction has correct register */
511         if (isRefField && (i == 0)) {
512             static_cast<RegOperand *>(&insn.GetOperand(static_cast<uint32>(seq[0])))->SetRefField(false);
513         }
514         /* Temporary comment the label:.Label.debug.callee */
515         if (i != (commaNum - 1)) {
516             (void)emitter.Emit(", ");
517         }
518         const uint32 commaNumForEmitLazy = 2;
519         if (!CGOptions::IsLazyBinding() || GetCG()->IsLibcore() || (mOp != MOP_wldr && mOp != MOP_xldr) ||
520             commaNum != commaNumForEmitLazy || i != 1 ||
521             !insn.GetOperand(static_cast<uint32>(seq[1])).IsMemoryAccessOperand()) {
522             continue;
523         }
524         /*
525          * Only check the last operand of ldr in lo12 mode.
526          * Check the second operand, if it's [AArch64MemOperand::kAddrModeLo12Li]
527          */
528         auto *memOpnd = static_cast<MemOperand *>(&insn.GetOperand(static_cast<uint32>(seq[1])));
529         if (memOpnd == nullptr || memOpnd->GetAddrMode() != MemOperand::kAddrModeLo12Li) {
530             continue;
531         }
532         const MIRSymbol *sym = memOpnd->GetSymbol();
533         if (sym->IsMuidFuncDefTab() || sym->IsMuidFuncUndefTab() || sym->IsMuidDataDefTab() ||
534             sym->IsMuidDataUndefTab()) {
535             (void)emitter.Emit("\n");
536             EmitLazyBindingRoutine(emitter, insn);
537         }
538     }
539     if (GetCG()->GenerateVerboseCG() || (GetCG()->GenerateVerboseAsm() && insn.IsComment())) {
540         const char *comment = insn.GetComment().c_str();
541         if (comment != nullptr && strlen(comment) > 0) {
542             (void)emitter.Emit("\t\t// ").Emit(comment);
543         }
544     }
545 
546     (void)emitter.Emit("\n");
547 }
548 
AsmStringOutputRegNum(bool isInt,uint32 regno,uint32 intBase,uint32 fpBase,std::string & strToEmit)549 static void AsmStringOutputRegNum(bool isInt, uint32 regno, uint32 intBase, uint32 fpBase, std::string &strToEmit)
550 {
551     regno_t newRegno;
552     if (isInt) {
553         CHECK_FATAL(regno >= intBase, "value overflow");
554         newRegno = regno - intBase;
555     } else {
556         newRegno = regno - fpBase;
557     }
558     if (newRegno > (kDecimalMax - 1)) {
559         uint32 tenth = newRegno / kDecimalMax;
560         strToEmit += '0' + static_cast<char>(tenth);
561         newRegno -= (kDecimalMax * tenth);
562     }
563     strToEmit += newRegno + '0';
564 }
565 
EmitInlineAsm(Emitter & emitter,const Insn & insn) const566 void AArch64AsmEmitter::EmitInlineAsm(Emitter &emitter, const Insn &insn) const
567 {
568     (void)emitter.Emit("\t//Inline asm begin\n\t");
569     auto &list1 = static_cast<ListOperand &>(insn.GetOperand(kAsmOutputListOpnd));
570     std::vector<RegOperand *> outOpnds;
571     for (auto *regOpnd : list1.GetOperands()) {
572         outOpnds.push_back(regOpnd);
573     }
574     auto &list2 = static_cast<ListOperand &>(insn.GetOperand(kAsmInputListOpnd));
575     std::vector<RegOperand *> inOpnds;
576     for (auto *regOpnd : list2.GetOperands()) {
577         inOpnds.push_back(regOpnd);
578     }
579     auto &list6 = static_cast<ListConstraintOperand &>(insn.GetOperand(kAsmOutputRegPrefixOpnd));
580     auto &list7 = static_cast<ListConstraintOperand &>(insn.GetOperand(kAsmInputRegPrefixOpnd));
581     MapleString asmStr = static_cast<StringOperand &>(insn.GetOperand(kAsmStringOpnd)).GetComment();
582     std::string stringToEmit;
583     auto IsMemAccess = [](char c) -> bool { return c == '['; };
584     auto EmitRegister = [&](const char *p, bool isInt, uint32 regNO, bool unDefRegSize) -> void {
585         if (IsMemAccess(p[0])) {
586             stringToEmit += "[x";
587             AsmStringOutputRegNum(isInt, regNO, R0, V0, stringToEmit);
588             stringToEmit += "]";
589         } else {
590             DEBUG_ASSERT((p[0] == 'w' || p[0] == 'x' || p[0] == 's' || p[0] == 'd' || p[0] == 'v'),
591                          "Asm invalid register type");
592             if ((p[0] == 'w' || p[0] == 'x') && unDefRegSize) {
593                 stringToEmit += 'x';
594             } else {
595                 stringToEmit += p[0];
596             }
597             if (!unDefRegSize) {
598                 isInt = (p[0] == 'w' || p[0] == 'x');
599             }
600             AsmStringOutputRegNum(isInt, regNO, R0, V0, stringToEmit);
601         }
602     };
603     for (size_t i = 0; i < asmStr.length(); ++i) {
604         switch (asmStr[i]) {
605             case '$': {
606                 char c = asmStr[++i];
607                 if ((c >= '0') && (c <= '9')) {
608                     auto val = static_cast<uint32>(c - '0');
609                     if (asmStr[i + 1] >= '0' && asmStr[i + 1] <= '9') {
610                         val = val * kDecimalMax + static_cast<uint32>(asmStr[++i] - '0');
611                     }
612                     if (val < outOpnds.size()) {
613                         const char *prefix = list6.stringList[val]->GetComment().c_str();
614                         RegOperand *opnd = outOpnds[val];
615                         EmitRegister(prefix, opnd->IsOfIntClass(), opnd->GetRegisterNumber(), true);
616                     } else {
617                         val -= static_cast<uint32>(outOpnds.size());
618                         CHECK_FATAL(val < inOpnds.size(), "Inline asm : invalid register constraint number");
619                         RegOperand *opnd = inOpnds[val];
620                         /* input is a immediate */
621                         const char *prefix = list7.stringList[val]->GetComment().c_str();
622                         if (prefix[0] == 'i') {
623                             stringToEmit += '#';
624                             for (size_t k = 1; k < list7.stringList[val]->GetComment().length(); ++k) {
625                                 stringToEmit += prefix[k];
626                             }
627                         } else {
628                             EmitRegister(prefix, opnd->IsOfIntClass(), opnd->GetRegisterNumber(), true);
629                         }
630                     }
631                 } else if (c == '{') {
632                     c = asmStr[++i];
633                     CHECK_FATAL(((c >= '0') && (c <= '9')), "Inline asm : invalid register constraint number");
634                     auto val = static_cast<uint32>(c - '0');
635                     if (asmStr[i + 1] >= '0' && asmStr[i + 1] <= '9') {
636                         val = val * kDecimalMax + static_cast<uint32>(asmStr[++i] - '0');
637                     }
638                     regno_t regno;
639                     bool isAddr = false;
640                     if (val < outOpnds.size()) {
641                         RegOperand *opnd = outOpnds[val];
642                         regno = opnd->GetRegisterNumber();
643                         isAddr = IsMemAccess(list6.stringList[val]->GetComment().c_str()[0]);
644                     } else {
645                         val -= static_cast<uint32>(outOpnds.size());
646                         CHECK_FATAL(val < inOpnds.size(), "Inline asm : invalid register constraint number");
647                         RegOperand *opnd = inOpnds[val];
648                         regno = opnd->GetRegisterNumber();
649                         DEBUG_ASSERT(list7.stringList[val]->GetComment().c_str() != nullptr,
650                             "list7 GetComment.c_str should not be nullptr");
651                         isAddr = IsMemAccess(list7.stringList[val]->GetComment().c_str()[0]);
652                     }
653                     c = asmStr[++i];
654                     CHECK_FATAL(c == ':', "Parsing error in inline asm string during emit");
655                     c = asmStr[++i];
656                     std::string prefix(1, c);
657                     if (c == 'a' || isAddr) {
658                         prefix = "[x";
659                     }
660                     EmitRegister(prefix.c_str(), true, regno, false);
661                     c = asmStr[++i];
662                     CHECK_FATAL(c == '}', "Parsing error in inline asm string during emit");
663                 }
664                 break;
665             }
666             case '\n': {
667                 stringToEmit += "\n\t";
668                 break;
669             }
670             default:
671                 stringToEmit += asmStr[i];
672         }
673     }
674     (void)emitter.Emit(stringToEmit);
675     (void)emitter.Emit("\n\t//Inline asm end\n");
676 }
677 
EmitClinitTail(Emitter & emitter,const Insn & insn) const678 void AArch64AsmEmitter::EmitClinitTail(Emitter &emitter, const Insn &insn) const
679 {
680     /*
681      * ldr x17, [xs, #112]
682      * ldr wzr, [x17]
683      */
684     const InsnDesc *md = &AArch64CG::kMd[MOP_clinit_tail];
685 
686     Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
687 
688     const OpndDesc *prop0 = md->opndMD[0];
689     A64OpndEmitVisitor visitor(emitter, prop0);
690 
691     /* emit "ldr  x17,[xs,#112]" */
692     (void)emitter.Emit("\t").Emit("ldr").Emit("\tx17, [");
693     opnd0->Accept(visitor);
694     (void)emitter.Emit(", #");
695     (void)emitter.Emit(static_cast<uint32>(ClassMetadata::OffsetOfInitState()));
696     (void)emitter.Emit("]");
697     (void)emitter.Emit("\n");
698 
699     /* emit "ldr  xzr, [x17]" */
700     (void)emitter.Emit("\t").Emit("ldr\txzr, [x17]\n");
701 }
702 
EmitLazyLoad(Emitter & emitter,const Insn & insn) const703 void AArch64AsmEmitter::EmitLazyLoad(Emitter &emitter, const Insn &insn) const
704 {
705     /*
706      * ldr wd, [xs]  # xd and xs should be differenct register
707      * ldr wd, [xd]
708      */
709     const InsnDesc *md = &AArch64CG::kMd[MOP_lazy_ldr];
710 
711     Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
712     Operand *opnd1 = &insn.GetOperand(kInsnSecondOpnd);
713     const OpndDesc *prop0 = md->opndMD[0];
714     const OpndDesc *prop1 = md->opndMD[1];
715     A64OpndEmitVisitor visitor(emitter, prop0);
716     A64OpndEmitVisitor visitor1(emitter, prop1);
717 
718     /* emit  "ldr wd, [xs]" */
719     (void)emitter.Emit("\t").Emit("ldr\t");
720 #ifdef USE_32BIT_REF
721     opnd0->Accept(visitor);
722 #else
723     opnd0->Accept(visitor1);
724 #endif
725     (void)emitter.Emit(", [");
726     opnd1->Accept(visitor1);
727     (void)emitter.Emit("]\t// lazy load.\n");
728 
729     /* emit "ldr wd, [xd]" */
730     (void)emitter.Emit("\t").Emit("ldr\t");
731     opnd0->Accept(visitor);
732     (void)emitter.Emit(", [");
733     opnd1->Accept(visitor1);
734     (void)emitter.Emit("]\t// lazy load.\n");
735 }
736 
EmitCounter(Emitter & emitter,const Insn & insn) const737 void AArch64AsmEmitter::EmitCounter(Emitter &emitter, const Insn &insn) const
738 {
739     /*
740      * adrp    x1, __profile_bb_table$$GetBoolean_bytecode+4
741      * ldr     w17, [x1, #:lo12:__profile_bb_table$$GetBoolean_bytecode+4]
742      * add     w17, w17, #1
743      * str     w17, [x1, #:lo12:__profile_bb_table$$GetBoolean_bytecode+4]
744      */
745     const InsnDesc *md = &AArch64CG::kMd[MOP_counter];
746 
747     Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
748     Operand *opnd1 = &insn.GetOperand(kInsnSecondOpnd);
749     const OpndDesc *prop0 = md->opndMD[kInsnFirstOpnd];
750     A64OpndEmitVisitor visitor(emitter, prop0);
751     StImmOperand *stImmOpnd = static_cast<StImmOperand *>(opnd1);
752     CHECK_FATAL(stImmOpnd != nullptr, "stImmOpnd is null in AArch64Emitter::EmitCounter");
753     /* emit nop for breakpoint */
754     if (GetCG()->GetCGOptions().WithDwarf()) {
755         (void)emitter.Emit("\t").Emit("nop").Emit("\n");
756     }
757 
758     /* emit adrp */
759     (void)emitter.Emit("\t").Emit("adrp").Emit("\t");
760     opnd0->Accept(visitor);
761     (void)emitter.Emit(",");
762     (void)emitter.Emit(stImmOpnd->GetName());
763     (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
764     (void)emitter.Emit("\n");
765     /* emit ldr */
766     (void)emitter.Emit("\t").Emit("ldr").Emit("\tw17, [");
767     opnd0->Accept(visitor);
768     (void)emitter.Emit(",");
769     (void)emitter.Emit("#");
770     (void)emitter.Emit(":lo12:").Emit(stImmOpnd->GetName());
771     (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
772     (void)emitter.Emit("]");
773     (void)emitter.Emit("\n");
774     /* emit add */
775     (void)emitter.Emit("\t").Emit("add").Emit("\tw17, w17, #1");
776     (void)emitter.Emit("\n");
777     /* emit str */
778     (void)emitter.Emit("\t").Emit("str").Emit("\tw17, [");
779     opnd0->Accept(visitor);
780     (void)emitter.Emit(",");
781     (void)emitter.Emit("#");
782     (void)emitter.Emit(":lo12:").Emit(stImmOpnd->GetName());
783     (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
784     (void)emitter.Emit("]");
785     (void)emitter.Emit("\n");
786 }
787 
EmitAdrpLabel(Emitter & emitter,const Insn & insn) const788 void AArch64AsmEmitter::EmitAdrpLabel(Emitter &emitter, const Insn &insn) const
789 {
790     /* adrp    xd, label
791      * add     xd, xd, #lo12:label
792      */
793     const InsnDesc *md = &AArch64CG::kMd[MOP_adrp_label];
794 
795     Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
796     Operand *opnd1 = &insn.GetOperand(kInsnSecondOpnd);
797     const OpndDesc *prop0 = md->opndMD[0];
798     A64OpndEmitVisitor visitor(emitter, prop0);
799     auto lidx = static_cast<ImmOperand *>(opnd1)->GetValue();
800 
801     /* adrp    xd, label */
802     (void)emitter.Emit("\t").Emit("adrp").Emit("\t");
803     opnd0->Accept(visitor);
804     (void)emitter.Emit(", ");
805     CHECK_NULL_FATAL(Globals::GetInstance()->GetBECommon()->GetMIRModule().CurFunction());
806     char *idx = strdup(std::to_string(
807         Globals::GetInstance()->GetBECommon()->GetMIRModule().CurFunction()->GetPuidx()).c_str());
808     CHECK_FATAL(idx != nullptr, "strdup failed");
809     (void)emitter.Emit(".L.").Emit(idx).Emit("__").Emit(lidx).Emit("\n");
810 
811     /* add     xd, xd, #lo12:label */
812     (void)emitter.Emit("\tadd\t");
813     opnd0->Accept(visitor);
814     (void)emitter.Emit(", ");
815     opnd0->Accept(visitor);
816     (void)emitter.Emit(", ");
817     (void)emitter.Emit(":lo12:").Emit(".L.").Emit(idx).Emit("__").Emit(lidx).Emit("\n");
818     (void)emitter.Emit("\n");
819     free(idx);
820     idx = nullptr;
821 }
822 
EmitAdrpLdr(Emitter & emitter,const Insn & insn) const823 void AArch64AsmEmitter::EmitAdrpLdr(Emitter &emitter, const Insn &insn) const
824 {
825     const InsnDesc *md = &AArch64CG::kMd[MOP_adrp_ldr];
826     Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
827     Operand *opnd1 = &insn.GetOperand(kInsnSecondOpnd);
828     const OpndDesc *prop0 = md->opndMD[0];
829     A64OpndEmitVisitor visitor(emitter, prop0);
830     auto *stImmOpnd = static_cast<StImmOperand *>(opnd1);
831     CHECK_FATAL(stImmOpnd != nullptr, "stImmOpnd is null in AArch64Emitter::EmitAdrpLdr");
832     /* emit nop for breakpoint */
833     if (GetCG()->GetCGOptions().WithDwarf()) {
834         (void)emitter.Emit("\t").Emit("nop").Emit("\n");
835     }
836 
837     (void)emitter.Emit("\t").Emit("adrp").Emit("\t");
838     opnd0->Accept(visitor);
839     (void)emitter.Emit(", ");
840     (void)emitter.Emit(stImmOpnd->GetName());
841     if (stImmOpnd->GetOffset() != 0) {
842         (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
843     }
844     (void)emitter.Emit("\n");
845 
846     (void)emitter.Emit("\tldr\t");
847     static_cast<RegOperand *>(opnd0)->SetRefField(true);
848     opnd0->Accept(visitor);
849     static_cast<RegOperand *>(opnd0)->SetRefField(false);
850     (void)emitter.Emit(", ");
851     (void)emitter.Emit("[");
852     opnd0->Accept(visitor);
853     (void)emitter.Emit(",");
854     (void)emitter.Emit("#");
855     (void)emitter.Emit(":lo12:").Emit(stImmOpnd->GetName());
856     if (stImmOpnd->GetOffset() != 0) {
857         (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
858     }
859     (void)emitter.Emit("]\n");
860 }
861 
EmitLazyLoadStatic(Emitter & emitter,const Insn & insn) const862 void AArch64AsmEmitter::EmitLazyLoadStatic(Emitter &emitter, const Insn &insn) const
863 {
864     /* adrp xd, :got:__staticDecoupleValueOffset$$xxx+offset
865      * ldr wd, [xd, #:got_lo12:__staticDecoupleValueOffset$$xxx+offset]
866      * ldr wzr, [xd]
867      */
868     const InsnDesc *md = &AArch64CG::kMd[MOP_lazy_ldr_static];
869 
870     Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
871     Operand *opnd1 = &insn.GetOperand(kInsnSecondOpnd);
872     const OpndDesc *prop0 = md->GetOpndDes(0);
873     A64OpndEmitVisitor visitor(emitter, prop0);
874     auto *stImmOpnd = static_cast<StImmOperand *>(opnd1);
875     CHECK_FATAL(stImmOpnd != nullptr, "stImmOpnd is null in AArch64Emitter::EmitLazyLoadStatic");
876 
877     /* emit "adrp xd, :got:__staticDecoupleValueOffset$$xxx+offset" */
878     (void)emitter.Emit("\t").Emit("adrp").Emit("\t");
879     opnd0->Accept(visitor);
880     (void)emitter.Emit(", ");
881     (void)emitter.Emit(stImmOpnd->GetName());
882     if (stImmOpnd->GetOffset() != 0) {
883         (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
884     }
885     (void)emitter.Emit("\t// lazy load static.\n");
886 
887     /* emit "ldr wd, [xd, #:got_lo12:__staticDecoupleValueOffset$$xxx+offset]" */
888     (void)emitter.Emit("\tldr\t");
889     static_cast<RegOperand *>(opnd0)->SetRefField(true);
890 #ifdef USE_32BIT_REF
891     const OpndDesc prop2(prop0->GetOperandType(), prop0->GetRegProp(), prop0->GetSize() / 2);
892     opnd0->Emit(emitter, &prop2); /* ldr wd, ... for terminal system */
893 #else
894     opnd0->Accept(visitor); /* ldr xd, ... for qemu */
895 #endif /* USE_32BIT_REF */
896     static_cast<RegOperand *>(opnd0)->SetRefField(false);
897     (void)emitter.Emit(", ");
898     (void)emitter.Emit("[");
899     opnd0->Accept(visitor);
900     (void)emitter.Emit(",");
901     (void)emitter.Emit("#");
902     (void)emitter.Emit(":lo12:").Emit(stImmOpnd->GetName());
903     if (stImmOpnd->GetOffset() != 0) {
904         (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
905     }
906     (void)emitter.Emit("]\t// lazy load static.\n");
907 
908     /* emit "ldr wzr, [xd]" */
909     (void)emitter.Emit("\t").Emit("ldr\twzr, [");
910     opnd0->Accept(visitor);
911     (void)emitter.Emit("]\t// lazy load static.\n");
912 }
913 
EmitArrayClassCacheLoad(Emitter & emitter,const Insn & insn) const914 void AArch64AsmEmitter::EmitArrayClassCacheLoad(Emitter &emitter, const Insn &insn) const
915 {
916     /* adrp xd, :got:__arrayClassCacheTable$$xxx+offset
917      * ldr wd, [xd, #:got_lo12:__arrayClassCacheTable$$xxx+offset]
918      * ldr wzr, [xd]
919      */
920     const InsnDesc *md = &AArch64CG::kMd[MOP_arrayclass_cache_ldr];
921     Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
922     Operand *opnd1 = &insn.GetOperand(kInsnSecondOpnd);
923     const OpndDesc *prop0 = md->GetOpndDes(kInsnFirstOpnd);
924     A64OpndEmitVisitor visitor(emitter, prop0);
925     auto *stImmOpnd = static_cast<StImmOperand *>(opnd1);
926     CHECK_FATAL(stImmOpnd != nullptr, "stImmOpnd is null in AArch64Emitter::EmitLazyLoadStatic");
927 
928     /* emit "adrp xd, :got:__arrayClassCacheTable$$xxx+offset" */
929     (void)emitter.Emit("\t").Emit("adrp").Emit("\t");
930     opnd0->Accept(visitor);
931     (void)emitter.Emit(", ");
932     (void)emitter.Emit(stImmOpnd->GetName());
933     if (stImmOpnd->GetOffset() != 0) {
934         (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
935     }
936     (void)emitter.Emit("\t// load array class.\n");
937 
938     /* emit "ldr wd, [xd, #:got_lo12:__arrayClassCacheTable$$xxx+offset]" */
939     (void)emitter.Emit("\tldr\t");
940     static_cast<RegOperand *>(opnd0)->SetRefField(true);
941 #ifdef USE_32BIT_REF
942     const OpndDesc prop2(prop0->GetOperandType(), prop0->GetRegProp(), prop0->GetSize() / 2);
943     A64OpndEmitVisitor visitor2(emitter, prop2);
944     opnd0->Accept(visitor2); /* ldr wd, ... for terminal system */
945 #else
946     opnd0->Accept(visitor); /* ldr xd, ... for qemu */
947 #endif /* USE_32BIT_REF */
948     static_cast<RegOperand *>(opnd0)->SetRefField(false);
949     (void)emitter.Emit(", ");
950     (void)emitter.Emit("[");
951     opnd0->Accept(visitor);
952     (void)emitter.Emit(",");
953     (void)emitter.Emit("#");
954     (void)emitter.Emit(":lo12:").Emit(stImmOpnd->GetName());
955     if (stImmOpnd->GetOffset() != 0) {
956         (void)emitter.Emit("+").Emit(stImmOpnd->GetOffset());
957     }
958     (void)emitter.Emit("]\t// load array class.\n");
959 
960     /* emit "ldr wzr, [xd]" */
961     (void)emitter.Emit("\t").Emit("ldr\twzr, [");
962     opnd0->Accept(visitor);
963     (void)emitter.Emit("]\t// check resolve array class.\n");
964 }
965 
966 /*
967  * intrinsic_get_add_int w0, xt, wt, ws, x1, x2, w3, label
968  * add    xt, x1, x2
969  * label:
970  * ldaxr  w0, [xt]
971  * add    wt, w0, w3
972  * stlxr  ws, wt, [xt]
973  * cbnz   ws, label
974  */
EmitGetAndAddInt(Emitter & emitter,const Insn & insn) const975 void AArch64AsmEmitter::EmitGetAndAddInt(Emitter &emitter, const Insn &insn) const
976 {
977     DEBUG_ASSERT(insn.GetOperandSize() > kInsnEighthOpnd, "ensure the oprands number");
978     (void)emitter.Emit("\t//\tstart of Unsafe.getAndAddInt.\n");
979     Operand *tempOpnd0 = &insn.GetOperand(kInsnSecondOpnd);
980     Operand *tempOpnd1 = &insn.GetOperand(kInsnThirdOpnd);
981     Operand *tempOpnd2 = &insn.GetOperand(kInsnFourthOpnd);
982     Operand *objOpnd = &insn.GetOperand(kInsnFifthOpnd);
983     Operand *offsetOpnd = &insn.GetOperand(kInsnSixthOpnd);
984     Operand *deltaOpnd = &insn.GetOperand(kInsnSeventhOpnd);
985     Operand *labelOpnd = &insn.GetOperand(kInsnEighthOpnd);
986     A64OpndEmitVisitor visitor(emitter, nullptr);
987     /* emit add. */
988     (void)emitter.Emit("\t").Emit("add").Emit("\t");
989     tempOpnd0->Accept(visitor);
990     (void)emitter.Emit(", ");
991     objOpnd->Accept(visitor);
992     (void)emitter.Emit(", ");
993     offsetOpnd->Accept(visitor);
994     (void)emitter.Emit("\n");
995     /* emit label. */
996     labelOpnd->Accept(visitor);
997     (void)emitter.Emit(":\n");
998     Operand *retVal = &insn.GetOperand(kInsnFirstOpnd);
999     const MOperator mOp = insn.GetMachineOpcode();
1000     const InsnDesc *md = &AArch64CG::kMd[mOp];
1001     const OpndDesc *retProp = md->opndMD[kInsnFirstOpnd];
1002     A64OpndEmitVisitor retVisitor(emitter, retProp);
1003     /* emit ldaxr */
1004     (void)emitter.Emit("\t").Emit("ldaxr").Emit("\t");
1005     retVal->Accept(retVisitor);
1006     (void)emitter.Emit(", [");
1007     tempOpnd0->Accept(visitor);
1008     (void)emitter.Emit("]\n");
1009     /* emit add. */
1010     (void)emitter.Emit("\t").Emit("add").Emit("\t");
1011     tempOpnd1->Accept(retVisitor);
1012     (void)emitter.Emit(", ");
1013     retVal->Accept(retVisitor);
1014     (void)emitter.Emit(", ");
1015     deltaOpnd->Accept(retVisitor);
1016     (void)emitter.Emit("\n");
1017     /* emit stlxr. */
1018     (void)emitter.Emit("\t").Emit("stlxr").Emit("\t");
1019     tempOpnd2->Accept(visitor);
1020     (void)emitter.Emit(", ");
1021     tempOpnd1->Accept(retVisitor);
1022     (void)emitter.Emit(", [");
1023     tempOpnd0->Accept(visitor);
1024     (void)emitter.Emit("]\n");
1025     /* emit cbnz. */
1026     (void)emitter.Emit("\t").Emit("cbnz").Emit("\t");
1027     tempOpnd2->Accept(visitor);
1028     (void)emitter.Emit(", ");
1029     labelOpnd->Accept(visitor);
1030     (void)emitter.Emit("\n");
1031     (void)emitter.Emit("\t//\tend of Unsafe.getAndAddInt.\n");
1032 }
1033 
1034 /*
1035  * intrinsic_get_set_int w0, xt, ws, x1, x2, w3, label
1036  * add    xt, x1, x2
1037  * label:
1038  * ldaxr  w0, [xt]
1039  * stlxr  ws, w3, [xt]
1040  * cbnz   ws, label
1041  */
EmitGetAndSetInt(Emitter & emitter,const Insn & insn) const1042 void AArch64AsmEmitter::EmitGetAndSetInt(Emitter &emitter, const Insn &insn) const
1043 {
1044     /* MOP_get_and_setI and MOP_get_and_setL have 7 operands */
1045     DEBUG_ASSERT(insn.GetOperandSize() > kInsnSeventhOpnd, "ensure the operands number");
1046     Operand *tempOpnd0 = &insn.GetOperand(kInsnSecondOpnd);
1047     Operand *tempOpnd1 = &insn.GetOperand(kInsnThirdOpnd);
1048     Operand *objOpnd = &insn.GetOperand(kInsnFourthOpnd);
1049     Operand *offsetOpnd = &insn.GetOperand(kInsnFifthOpnd);
1050     A64OpndEmitVisitor visitor(emitter, nullptr);
1051     /* add    x1, x1, x2 */
1052     (void)emitter.Emit("\tadd\t");
1053     tempOpnd0->Accept(visitor);
1054     (void)emitter.Emit(", ");
1055     objOpnd->Accept(visitor);
1056     (void)emitter.Emit(", ");
1057     offsetOpnd->Accept(visitor);
1058     (void)emitter.Emit("\n");
1059     Operand *labelOpnd = &insn.GetOperand(kInsnSeventhOpnd);
1060     /* label: */
1061     labelOpnd->Accept(visitor);
1062     (void)emitter.Emit(":\n");
1063     Operand *retVal = &insn.GetOperand(kInsnFirstOpnd);
1064     /* ldaxr  w0, [xt] */
1065     (void)emitter.Emit("\tldaxr\t");
1066     retVal->Accept(visitor);
1067     (void)emitter.Emit(", [");
1068     tempOpnd0->Accept(visitor);
1069     (void)emitter.Emit("]\n");
1070     Operand *newValueOpnd = &insn.GetOperand(kInsnSixthOpnd);
1071     /* stlxr  ws, w3, [xt] */
1072     (void)emitter.Emit("\tstlxr\t");
1073     tempOpnd1->Accept(visitor);
1074     (void)emitter.Emit(", ");
1075     newValueOpnd->Accept(visitor);
1076     (void)emitter.Emit(", [");
1077     tempOpnd0->Accept(visitor);
1078     (void)emitter.Emit("]\n");
1079     /* cbnz   w2, label */
1080     (void)emitter.Emit("\tcbnz\t");
1081     tempOpnd1->Accept(visitor);
1082     (void)emitter.Emit(", ");
1083     labelOpnd->Accept(visitor);
1084     (void)emitter.Emit("\n");
1085 }
1086 
1087 /*
1088  * intrinsic_string_indexof w0, x1, w2, x3, w4, x5, x6, x7, x8, x9, w10,
1089  *                          Label.FIRST_LOOP, Label.STR2_NEXT, Label.STR1_LOOP,
1090  *                          Label.STR1_NEXT, Label.LAST_WORD, Label.NOMATCH, Label.RET
1091  * cmp       w4, w2
1092  * b.gt      .Label.NOMATCH
1093  * sub       w2, w2, w4
1094  * sub       w4, w4, #8
1095  * mov       w10, w2
1096  * uxtw      x4, w4
1097  * uxtw      x2, w2
1098  * add       x3, x3, x4
1099  * add       x1, x1, x2
1100  * neg       x4, x4
1101  * neg       x2, x2
1102  * ldr       x5, [x3,x4]
1103  * .Label.FIRST_LOOP:
1104  * ldr       x7, [x1,x2]
1105  * cmp       x5, x7
1106  * b.eq      .Label.STR1_LOOP
1107  * .Label.STR2_NEXT:
1108  * adds      x2, x2, #1
1109  * b.le      .Label.FIRST_LOOP
1110  * b         .Label.NOMATCH
1111  * .Label.STR1_LOOP:
1112  * adds      x8, x4, #8
1113  * add       x9, x2, #8
1114  * b.ge      .Label.LAST_WORD
1115  * .Label.STR1_NEXT:
1116  * ldr       x6, [x3,x8]
1117  * ldr       x7, [x1,x9]
1118  * cmp       x6, x7
1119  * b.ne      .Label.STR2_NEXT
1120  * adds      x8, x8, #8
1121  * add       x9, x9, #8
1122  * b.lt      .Label.STR1_NEXT
1123  * .Label.LAST_WORD:
1124  * ldr       x6, [x3]
1125  * sub       x9, x1, x4
1126  * ldr       x7, [x9,x2]
1127  * cmp       x6, x7
1128  * b.ne      .Label.STR2_NEXT
1129  * add       w0, w10, w2
1130  * b         .Label.RET
1131  * .Label.NOMATCH:
1132  * mov       w0, #-1
1133  * .Label.RET:
1134  */
EmitStringIndexOf(Emitter & emitter,const Insn & insn) const1135 void AArch64AsmEmitter::EmitStringIndexOf(Emitter &emitter, const Insn &insn) const
1136 {
1137     /* MOP_string_indexof has 18 operands */
1138     DEBUG_ASSERT(insn.GetOperandSize() == 18, "ensure the operands number");
1139     Operand *patternLengthOpnd = &insn.GetOperand(kInsnFifthOpnd);
1140     Operand *srcLengthOpnd = &insn.GetOperand(kInsnThirdOpnd);
1141     const std::string patternLengthReg =
1142         AArch64CG::intRegNames[AArch64CG::kR64List][static_cast<RegOperand *>(patternLengthOpnd)->GetRegisterNumber()];
1143     const std::string srcLengthReg =
1144         AArch64CG::intRegNames[AArch64CG::kR64List][static_cast<RegOperand *>(srcLengthOpnd)->GetRegisterNumber()];
1145     A64OpndEmitVisitor visitor(emitter, nullptr);
1146     /* cmp       w4, w2 */
1147     (void)emitter.Emit("\tcmp\t");
1148     patternLengthOpnd->Accept(visitor);
1149     (void)emitter.Emit(", ");
1150     srcLengthOpnd->Accept(visitor);
1151     (void)emitter.Emit("\n");
1152     /* the 16th operand of MOP_string_indexof is Label.NOMATCH */
1153     Operand *labelNoMatch = &insn.GetOperand(16);
1154     /* b.gt      Label.NOMATCH */
1155     (void)emitter.Emit("\tb.gt\t");
1156     labelNoMatch->Accept(visitor);
1157     (void)emitter.Emit("\n");
1158     /* sub       w2, w2, w4 */
1159     (void)emitter.Emit("\tsub\t");
1160     srcLengthOpnd->Accept(visitor);
1161     (void)emitter.Emit(", ");
1162     srcLengthOpnd->Accept(visitor);
1163     (void)emitter.Emit(", ");
1164     patternLengthOpnd->Accept(visitor);
1165     (void)emitter.Emit("\n");
1166     /* sub       w4, w4, #8 */
1167     (void)emitter.Emit("\tsub\t");
1168     patternLengthOpnd->Accept(visitor);
1169     (void)emitter.Emit(", ");
1170     patternLengthOpnd->Accept(visitor);
1171     (void)emitter.Emit(", #8\n");
1172     /* the 10th operand of MOP_string_indexof is w10 */
1173     Operand *resultTmp = &insn.GetOperand(10);
1174     /* mov       w10, w2 */
1175     (void)emitter.Emit("\tmov\t");
1176     resultTmp->Accept(visitor);
1177     (void)emitter.Emit(", ");
1178     srcLengthOpnd->Accept(visitor);
1179     (void)emitter.Emit("\n");
1180     /* uxtw      x4, w4 */
1181     (void)emitter.Emit("\tuxtw\t").Emit(patternLengthReg);
1182     (void)emitter.Emit(", ");
1183     patternLengthOpnd->Accept(visitor);
1184     (void)emitter.Emit("\n");
1185     /* uxtw      x2, w2 */
1186     (void)emitter.Emit("\tuxtw\t").Emit(srcLengthReg);
1187     (void)emitter.Emit(", ");
1188     srcLengthOpnd->Accept(visitor);
1189     (void)emitter.Emit("\n");
1190     Operand *patternStringBaseOpnd = &insn.GetOperand(kInsnFourthOpnd);
1191     /* add       x3, x3, x4 */
1192     (void)emitter.Emit("\tadd\t");
1193     patternStringBaseOpnd->Accept(visitor);
1194     (void)emitter.Emit(", ");
1195     patternStringBaseOpnd->Accept(visitor);
1196     (void)emitter.Emit(", ").Emit(patternLengthReg);
1197     (void)emitter.Emit("\n");
1198     Operand *srcStringBaseOpnd = &insn.GetOperand(kInsnSecondOpnd);
1199     /* add       x1, x1, x2 */
1200     (void)emitter.Emit("\tadd\t");
1201     srcStringBaseOpnd->Accept(visitor);
1202     (void)emitter.Emit(", ");
1203     srcStringBaseOpnd->Accept(visitor);
1204     (void)emitter.Emit(", ").Emit(srcLengthReg);
1205     (void)emitter.Emit("\n");
1206     /* neg       x4, x4 */
1207     (void)emitter.Emit("\tneg\t").Emit(patternLengthReg);
1208     (void)emitter.Emit(", ").Emit(patternLengthReg);
1209     (void)emitter.Emit("\n");
1210     /* neg       x2, x2 */
1211     (void)emitter.Emit("\tneg\t").Emit(srcLengthReg);
1212     (void)emitter.Emit(", ").Emit(srcLengthReg);
1213     (void)emitter.Emit("\n");
1214     Operand *first = &insn.GetOperand(kInsnSixthOpnd);
1215     /* ldr       x5, [x3,x4] */
1216     (void)emitter.Emit("\tldr\t");
1217     first->Accept(visitor);
1218     (void)emitter.Emit(", [");
1219     patternStringBaseOpnd->Accept(visitor);
1220     (void)emitter.Emit(",").Emit(patternLengthReg);
1221     (void)emitter.Emit("]\n");
1222     /* the 11th operand of MOP_string_indexof is Label.FIRST_LOOP */
1223     Operand *labelFirstLoop = &insn.GetOperand(11);
1224     /* .Label.FIRST_LOOP: */
1225     labelFirstLoop->Accept(visitor);
1226     (void)emitter.Emit(":\n");
1227     /* the 7th operand of MOP_string_indexof is x7 */
1228     Operand *ch2 = &insn.GetOperand(7);
1229     /* ldr       x7, [x1,x2] */
1230     (void)emitter.Emit("\tldr\t");
1231     ch2->Accept(visitor);
1232     (void)emitter.Emit(", [");
1233     srcStringBaseOpnd->Accept(visitor);
1234     (void)emitter.Emit(",").Emit(srcLengthReg);
1235     (void)emitter.Emit("]\n");
1236     /* cmp       x5, x7 */
1237     (void)emitter.Emit("\tcmp\t");
1238     first->Accept(visitor);
1239     (void)emitter.Emit(", ");
1240     ch2->Accept(visitor);
1241     (void)emitter.Emit("\n");
1242     /* the 13th operand of MOP_string_indexof is Label.STR1_LOOP */
1243     Operand *labelStr1Loop = &insn.GetOperand(13);
1244     /* b.eq      .Label.STR1_LOOP */
1245     (void)emitter.Emit("\tb.eq\t");
1246     labelStr1Loop->Accept(visitor);
1247     (void)emitter.Emit("\n");
1248     /* the 12th operand of MOP_string_indexof is Label.STR2_NEXT */
1249     Operand *labelStr2Next = &insn.GetOperand(12);
1250     /* .Label.STR2_NEXT: */
1251     labelStr2Next->Accept(visitor);
1252     (void)emitter.Emit(":\n");
1253     /* adds      x2, x2, #1 */
1254     (void)emitter.Emit("\tadds\t").Emit(srcLengthReg);
1255     (void)emitter.Emit(", ").Emit(srcLengthReg);
1256     (void)emitter.Emit(", #1\n");
1257     /* b.le      .Label.FIRST_LOOP */
1258     (void)emitter.Emit("\tb.le\t");
1259     labelFirstLoop->Accept(visitor);
1260     (void)emitter.Emit("\n");
1261     /* b         .Label.NOMATCH */
1262     (void)emitter.Emit("\tb\t");
1263     labelNoMatch->Accept(visitor);
1264     (void)emitter.Emit("\n");
1265     /* .Label.STR1_LOOP: */
1266     labelStr1Loop->Accept(visitor);
1267     (void)emitter.Emit(":\n");
1268     /* the 8th operand of MOP_string_indexof is x8 */
1269     Operand *tmp1 = &insn.GetOperand(kInsnEighthOpnd);
1270     /* adds      x8, x4, #8 */
1271     (void)emitter.Emit("\tadds\t");
1272     tmp1->Accept(visitor);
1273     (void)emitter.Emit(", ").Emit(patternLengthReg);
1274     (void)emitter.Emit(", #8\n");
1275     /* the 9th operand of MOP_string_indexof is x9 */
1276     Operand *tmp2 = &insn.GetOperand(9);
1277     /* add       x9, x2, #8 */
1278     (void)emitter.Emit("\tadd\t");
1279     tmp2->Accept(visitor);
1280     (void)emitter.Emit(", ").Emit(srcLengthReg);
1281     (void)emitter.Emit(", #8\n");
1282     /* the 15th operand of MOP_string_indexof is Label.LAST_WORD */
1283     Operand *labelLastWord = &insn.GetOperand(15);
1284     /* b.ge      .Label.LAST_WORD */
1285     (void)emitter.Emit("\tb.ge\t");
1286     labelLastWord->Accept(visitor);
1287     (void)emitter.Emit("\n");
1288     /* the 14th operand of MOP_string_indexof is Label.STR1_NEXT */
1289     Operand *labelStr1Next = &insn.GetOperand(14);
1290     /* .Label.STR1_NEXT: */
1291     labelStr1Next->Accept(visitor);
1292     (void)emitter.Emit(":\n");
1293     /* the 6th operand of MOP_string_indexof is x6 */
1294     Operand *ch1 = &insn.GetOperand(6);
1295     /* ldr       x6, [x3,x8] */
1296     (void)emitter.Emit("\tldr\t");
1297     ch1->Accept(visitor);
1298     (void)emitter.Emit(", [");
1299     patternStringBaseOpnd->Accept(visitor);
1300     (void)emitter.Emit(",");
1301     tmp1->Accept(visitor);
1302     (void)emitter.Emit("]\n");
1303     /* ldr       x7, [x1,x9] */
1304     (void)emitter.Emit("\tldr\t");
1305     ch2->Accept(visitor);
1306     (void)emitter.Emit(", [");
1307     srcStringBaseOpnd->Accept(visitor);
1308     (void)emitter.Emit(",");
1309     tmp2->Accept(visitor);
1310     (void)emitter.Emit("]\n");
1311     /* cmp       x6, x7 */
1312     (void)emitter.Emit("\tcmp\t");
1313     ch1->Accept(visitor);
1314     (void)emitter.Emit(", ");
1315     ch2->Accept(visitor);
1316     (void)emitter.Emit("\n");
1317     /* b.ne      .Label.STR2_NEXT */
1318     (void)emitter.Emit("\tb.ne\t");
1319     labelStr2Next->Accept(visitor);
1320     (void)emitter.Emit("\n");
1321     /* adds      x8, x8, #8 */
1322     (void)emitter.Emit("\tadds\t");
1323     tmp1->Accept(visitor);
1324     (void)emitter.Emit(", ");
1325     tmp1->Accept(visitor);
1326     (void)emitter.Emit(", #8\n");
1327     /* add       x9, x9, #8 */
1328     (void)emitter.Emit("\tadd\t");
1329     tmp2->Accept(visitor);
1330     (void)emitter.Emit(", ");
1331     tmp2->Accept(visitor);
1332     (void)emitter.Emit(", #8\n");
1333     /* b.lt      .Label.STR1_NEXT */
1334     (void)emitter.Emit("\tb.lt\t");
1335     labelStr1Next->Accept(visitor);
1336     (void)emitter.Emit("\n");
1337     /* .Label.LAST_WORD: */
1338     labelLastWord->Accept(visitor);
1339     (void)emitter.Emit(":\n");
1340     /* ldr       x6, [x3] */
1341     (void)emitter.Emit("\tldr\t");
1342     ch1->Accept(visitor);
1343     (void)emitter.Emit(", [");
1344     patternStringBaseOpnd->Accept(visitor);
1345     (void)emitter.Emit("]\n");
1346     /* sub       x9, x1, x4 */
1347     (void)emitter.Emit("\tsub\t");
1348     tmp2->Accept(visitor);
1349     (void)emitter.Emit(", ");
1350     srcStringBaseOpnd->Accept(visitor);
1351     (void)emitter.Emit(", ").Emit(patternLengthReg);
1352     (void)emitter.Emit("\n");
1353     /* ldr       x7, [x9,x2] */
1354     (void)emitter.Emit("\tldr\t");
1355     ch2->Accept(visitor);
1356     (void)emitter.Emit(", [");
1357     tmp2->Accept(visitor);
1358     (void)emitter.Emit(", ").Emit(srcLengthReg);
1359     (void)emitter.Emit("]\n");
1360     /* cmp       x6, x7 */
1361     (void)emitter.Emit("\tcmp\t");
1362     ch1->Accept(visitor);
1363     (void)emitter.Emit(", ");
1364     ch2->Accept(visitor);
1365     (void)emitter.Emit("\n");
1366     /* b.ne      .Label.STR2_NEXT */
1367     (void)emitter.Emit("\tb.ne\t");
1368     labelStr2Next->Accept(visitor);
1369     (void)emitter.Emit("\n");
1370     Operand *retVal = &insn.GetOperand(kInsnFirstOpnd);
1371     /* add       w0, w10, w2 */
1372     (void)emitter.Emit("\tadd\t");
1373     retVal->Accept(visitor);
1374     (void)emitter.Emit(", ");
1375     resultTmp->Accept(visitor);
1376     (void)emitter.Emit(", ");
1377     srcLengthOpnd->Accept(visitor);
1378     (void)emitter.Emit("\n");
1379     /* the 17th operand of MOP_string_indexof Label.ret */
1380     Operand *labelRet = &insn.GetOperand(17);
1381     /* b         .Label.ret */
1382     (void)emitter.Emit("\tb\t");
1383     labelRet->Accept(visitor);
1384     (void)emitter.Emit("\n");
1385     /* .Label.NOMATCH: */
1386     labelNoMatch->Accept(visitor);
1387     (void)emitter.Emit(":\n");
1388     /* mov       w0, #-1 */
1389     (void)emitter.Emit("\tmov\t");
1390     retVal->Accept(visitor);
1391     (void)emitter.Emit(", #-1\n");
1392     /* .Label.ret: */
1393     labelRet->Accept(visitor);
1394     (void)emitter.Emit(":\n");
1395 }
1396 
1397 /*
1398  * intrinsic_compare_swap_int x0, xt, xs, x1, x2, w3, w4, lable1, label2
1399  * add       xt, x1, x2
1400  * label1:
1401  * ldaxr     ws, [xt]
1402  * cmp       ws, w3
1403  * b.ne      label2
1404  * stlxr     ws, w4, [xt]
1405  * cbnz      ws, label1
1406  * label2:
1407  * cset      x0, eq
1408  */
EmitCompareAndSwapInt(Emitter & emitter,const Insn & insn) const1409 void AArch64AsmEmitter::EmitCompareAndSwapInt(Emitter &emitter, const Insn &insn) const
1410 {
1411     /* MOP_compare_and_swapI and MOP_compare_and_swapL have 8 operands */
1412     DEBUG_ASSERT(insn.GetOperandSize() > kInsnEighthOpnd, "ensure the operands number");
1413     const MOperator mOp = insn.GetMachineOpcode();
1414     const InsnDesc *md = &AArch64CG::kMd[mOp];
1415     Operand *temp0 = &insn.GetOperand(kInsnSecondOpnd);
1416     Operand *temp1 = &insn.GetOperand(kInsnThirdOpnd);
1417     Operand *obj = &insn.GetOperand(kInsnFourthOpnd);
1418     Operand *offset = &insn.GetOperand(kInsnFifthOpnd);
1419     A64OpndEmitVisitor visitor(emitter, nullptr);
1420     /* add       xt, x1, x2 */
1421     (void)emitter.Emit("\tadd\t");
1422     temp0->Accept(visitor);
1423     (void)emitter.Emit(", ");
1424     obj->Accept(visitor);
1425     (void)emitter.Emit(", ");
1426     offset->Accept(visitor);
1427     (void)emitter.Emit("\n");
1428     Operand *label1 = &insn.GetOperand(kInsnEighthOpnd);
1429     /* label1: */
1430     label1->Accept(visitor);
1431     (void)emitter.Emit(":\n");
1432     /* ldaxr     ws, [xt] */
1433     (void)emitter.Emit("\tldaxr\t");
1434     temp1->Accept(visitor);
1435     (void)emitter.Emit(", [");
1436     temp0->Accept(visitor);
1437     (void)emitter.Emit("]\n");
1438     Operand *expectedValue = &insn.GetOperand(kInsnSixthOpnd);
1439     const OpndDesc *expectedValueProp = md->opndMD[kInsnSixthOpnd];
1440     /* cmp       ws, w3 */
1441     (void)emitter.Emit("\tcmp\t");
1442     temp1->Accept(visitor);
1443     (void)emitter.Emit(", ");
1444     A64OpndEmitVisitor visitorExpect(emitter, expectedValueProp);
1445     expectedValue->Accept(visitorExpect);
1446     (void)emitter.Emit("\n");
1447     constexpr uint32 kInsnNinethOpnd = 8;
1448     Operand *label2 = &insn.GetOperand(kInsnNinethOpnd);
1449     /* b.ne      label2 */
1450     (void)emitter.Emit("\tbne\t");
1451     label2->Accept(visitor);
1452     (void)emitter.Emit("\n");
1453     Operand *newValue = &insn.GetOperand(kInsnSeventhOpnd);
1454     /* stlxr     ws, w4, [xt] */
1455     (void)emitter.Emit("\tstlxr\t");
1456     (void)emitter.Emit(
1457         AArch64CG::intRegNames[AArch64CG::kR32List][static_cast<RegOperand *>(temp1)->GetRegisterNumber()]);
1458     (void)emitter.Emit(", ");
1459     newValue->Accept(visitor);
1460     (void)emitter.Emit(", [");
1461     temp0->Accept(visitor);
1462     (void)emitter.Emit("]\n");
1463     /* cbnz      ws, label1 */
1464     (void)emitter.Emit("\tcbnz\t");
1465     (void)emitter.Emit(
1466         AArch64CG::intRegNames[AArch64CG::kR32List][static_cast<RegOperand *>(temp1)->GetRegisterNumber()]);
1467     (void)emitter.Emit(", ");
1468     label1->Accept(visitor);
1469     (void)emitter.Emit("\n");
1470     /* label2: */
1471     label2->Accept(visitor);
1472     (void)emitter.Emit(":\n");
1473     Operand *retVal = &insn.GetOperand(kInsnFirstOpnd);
1474     /* cset      x0, eq */
1475     (void)emitter.Emit("\tcset\t");
1476     retVal->Accept(visitor);
1477     (void)emitter.Emit(", EQ\n");
1478 }
1479 
EmitCTlsDescRel(Emitter & emitter,const Insn & insn) const1480 void AArch64AsmEmitter::EmitCTlsDescRel(Emitter &emitter, const Insn &insn) const
1481 {
1482     const InsnDesc *md = &AArch64CG::kMd[MOP_tls_desc_rel];
1483     Operand *result = &insn.GetOperand(kInsnFirstOpnd);
1484     Operand *src = &insn.GetOperand(kInsnSecondOpnd);
1485     Operand *symbol = &insn.GetOperand(kInsnThirdOpnd);
1486     auto stImmOpnd = static_cast<StImmOperand *>(symbol);
1487     A64OpndEmitVisitor resultVisitor(emitter, md->opndMD[0]);
1488     A64OpndEmitVisitor srcVisitor(emitter, md->opndMD[1]);
1489     (void)emitter.Emit("\t").Emit("add").Emit("\t");
1490     result->Accept(resultVisitor);
1491     (void)emitter.Emit(", ");
1492     src->Accept(srcVisitor);
1493     (void)emitter.Emit(", #:tprel_hi12:").Emit(stImmOpnd->GetName()).Emit(", lsl #12\n");
1494     (void)emitter.Emit("\t").Emit("add").Emit("\t");
1495     result->Accept(resultVisitor);
1496     (void)emitter.Emit(", ");
1497     result->Accept(resultVisitor);
1498     (void)emitter.Emit(", #:tprel_lo12_nc:").Emit(stImmOpnd->GetName()).Emit("\n");
1499 }
1500 
EmitCTlsDescCall(Emitter & emitter,const Insn & insn) const1501 void AArch64AsmEmitter::EmitCTlsDescCall(Emitter &emitter, const Insn &insn) const
1502 {
1503     const InsnDesc *md = &AArch64CG::kMd[MOP_tls_desc_call];
1504     Operand *func = &insn.GetOperand(kInsnFirstOpnd);
1505     Operand *symbol = &insn.GetOperand(kInsnThirdOpnd);
1506     const OpndDesc *prop = md->opndMD[0];
1507     auto *stImmOpnd = static_cast<StImmOperand *>(symbol);
1508     const std::string &symName = stImmOpnd->GetName();
1509     A64OpndEmitVisitor funcVisitor(emitter, prop);
1510     /*  adrp    x0, :tlsdesc:symbol */
1511     (void)emitter.Emit("\t").Emit("adrp\tx0, :tlsdesc:").Emit(symName).Emit("\n");
1512     /*  ldr x1, [x0, #tlsdesc_lo12:symbol] */
1513     (void)emitter.Emit("\t").Emit("ldr").Emit("\t");
1514     func->Accept(funcVisitor);
1515     (void)emitter.Emit(", [x0, #:tlsdesc_lo12:").Emit(symName).Emit("]\n");
1516     /*  add x0 ,#tlsdesc_lo12:symbol */
1517     (void)emitter.Emit("\t").Emit("add\tx0, x0, :tlsdesc_lo12:").Emit(symName).Emit("\n");
1518     /* .tlsdesccall <symbolName> */
1519     (void)emitter.Emit("\t").Emit(".tlsdesccall").Emit("\t").Emit(symName).Emit("\n");
1520     /* blr xd */
1521     (void)emitter.Emit("\t").Emit("blr").Emit("\t");
1522     func->Accept(funcVisitor);
1523     (void)emitter.Emit("\n");
1524 }
1525 
EmitSyncLockTestSet(Emitter & emitter,const Insn & insn) const1526 void AArch64AsmEmitter::EmitSyncLockTestSet(Emitter &emitter, const Insn &insn) const
1527 {
1528     const InsnDesc *md = &AArch64CG::kMd[insn.GetMachineOpcode()];
1529     auto *result = &insn.GetOperand(kInsnFirstOpnd);
1530     auto *temp = &insn.GetOperand(kInsnSecondOpnd);
1531     auto *addr = &insn.GetOperand(kInsnThirdOpnd);
1532     auto *value = &insn.GetOperand(kInsnFourthOpnd);
1533     auto *label = &insn.GetOperand(kInsnFifthOpnd);
1534     A64OpndEmitVisitor resultVisitor(emitter, md->opndMD[kInsnFirstOpnd]);
1535     A64OpndEmitVisitor tempVisitor(emitter, md->opndMD[kInsnSecondOpnd]);
1536     A64OpndEmitVisitor addrVisitor(emitter, md->opndMD[kInsnThirdOpnd]);
1537     A64OpndEmitVisitor valueVisitor(emitter, md->opndMD[kInsnFourthOpnd]);
1538     A64OpndEmitVisitor labelVisitor(emitter, md->opndMD[kInsnFifthOpnd]);
1539     /* label: */
1540     label->Accept(labelVisitor);
1541     (void)emitter.Emit(":\n");
1542     /* ldxr x0, [x2] */
1543     (void)emitter.Emit("\t").Emit("ldxr").Emit("\t");
1544     result->Accept(resultVisitor);
1545     (void)emitter.Emit(", [");
1546     addr->Accept(addrVisitor);
1547     (void)emitter.Emit("]\n");
1548     /* stxr w1, x3, [x2] */
1549     (void)emitter.Emit("\t").Emit("stxr").Emit("\t");
1550     temp->Accept(tempVisitor);
1551     (void)emitter.Emit(", ");
1552     value->Accept(valueVisitor);
1553     (void)emitter.Emit(", [");
1554     addr->Accept(addrVisitor);
1555     (void)emitter.Emit("]\n");
1556     /* cbnz w1, label */
1557     (void)emitter.Emit("\t").Emit("cbnz").Emit("\t");
1558     temp->Accept(tempVisitor);
1559     (void)emitter.Emit(", ");
1560     label->Accept(labelVisitor);
1561     (void)emitter.Emit("\n");
1562     /* dmb ish */
1563     (void)emitter.Emit("\t").Emit("dmb").Emit("\t").Emit("ish").Emit("\n");
1564 }
1565 
EmitCheckThrowPendingException(Emitter & emitter,Insn & insn) const1566 void AArch64AsmEmitter::EmitCheckThrowPendingException(Emitter &emitter, Insn &insn) const
1567 {
1568     /*
1569      * mrs x16, TPIDR_EL0
1570      * ldr x16, [x16, #64]
1571      * ldr x16, [x16, #8]
1572      * cbz x16, .lnoexception
1573      * bl MCC_ThrowPendingException
1574      * .lnoexception:
1575      */
1576     (void)emitter.Emit("\t").Emit("mrs").Emit("\tx16, TPIDR_EL0");
1577     (void)emitter.Emit("\n");
1578     (void)emitter.Emit("\t").Emit("ldr").Emit("\tx16, [x16, #64]");
1579     (void)emitter.Emit("\n");
1580     (void)emitter.Emit("\t").Emit("ldr").Emit("\tx16, [x16, #8]");
1581     (void)emitter.Emit("\n");
1582     (void)emitter.Emit("\t").Emit("cbz").Emit("\tx16, .lnoeh.").Emit(maplebe::CG::GetCurCGFunc()->GetName());
1583     (void)emitter.Emit("\n");
1584     (void)emitter.Emit("\t").Emit("bl").Emit("\tMCC_ThrowPendingException");
1585     (void)emitter.Emit("\n");
1586     (void)emitter.Emit(".lnoeh.").Emit(maplebe::CG::GetCurCGFunc()->GetName()).Emit(":");
1587     (void)emitter.Emit("\n");
1588 }
1589 
EmitLazyBindingRoutine(Emitter & emitter,const Insn & insn) const1590 void AArch64AsmEmitter::EmitLazyBindingRoutine(Emitter &emitter, const Insn &insn) const
1591 {
1592     /* ldr xzr, [xs] */
1593     const InsnDesc *md = &AArch64CG::kMd[MOP_adrp_ldr];
1594 
1595     Operand *opnd0 = &insn.GetOperand(kInsnFirstOpnd);
1596     const OpndDesc *prop0 = md->opndMD[0];
1597     A64OpndEmitVisitor visitor(emitter, prop0);
1598 
1599     /* emit "ldr  xzr,[xs]" */
1600 #ifdef USE_32BIT_REF
1601     (void)emitter.Emit("\t").Emit("ldr").Emit("\twzr, [");
1602 #else
1603     (void)emitter.Emit("\t").Emit("ldr").Emit("\txzr, [");
1604 #endif /* USE_32BIT_REF */
1605     opnd0->Accept(visitor);
1606     (void)emitter.Emit("]");
1607     (void)emitter.Emit("\t// Lazy binding\n");
1608 }
1609 
PrepareVectorOperand(RegOperand * regOpnd,uint32 & compositeOpnds,Insn & insn) const1610 void AArch64AsmEmitter::PrepareVectorOperand(RegOperand *regOpnd, uint32 &compositeOpnds, Insn &insn) const
1611 {
1612     VectorRegSpec *vecSpec = static_cast<VectorInsn &>(insn).GetAndRemoveRegSpecFromList();
1613     compositeOpnds = vecSpec->compositeOpnds ? vecSpec->compositeOpnds : compositeOpnds;
1614     regOpnd->SetVecLanePosition(vecSpec->vecLane);
1615     switch (insn.GetMachineOpcode()) {
1616         case MOP_vanduuu:
1617         case MOP_vxoruuu:
1618         case MOP_voruuu:
1619         case MOP_vnotuu:
1620         case MOP_vextuuui: {
1621             regOpnd->SetVecLaneSize(k8ByteSize);
1622             regOpnd->SetVecElementSize(k8BitSize);
1623             break;
1624         }
1625         case MOP_vandvvv:
1626         case MOP_vxorvvv:
1627         case MOP_vorvvv:
1628         case MOP_vnotvv:
1629         case MOP_vextvvvi: {
1630             regOpnd->SetVecLaneSize(k16ByteSize);
1631             regOpnd->SetVecElementSize(k8BitSize);
1632             break;
1633         }
1634         default: {
1635             regOpnd->SetVecLaneSize(vecSpec->vecLaneMax);
1636             regOpnd->SetVecElementSize(vecSpec->vecElementSize);
1637             break;
1638         }
1639     }
1640 }
1641 
1642 struct CfiDescr {
1643     const std::string name;
1644     uint32 opndCount;
1645     /* create 3 OperandType array to store cfi instruction's operand type */
1646     std::array<Operand::OperandType, 3> opndTypes;
1647 };
1648 
1649 static CfiDescr cfiDescrTable[cfi::kOpCfiLast + 1] = {
1650 #define CFI_DEFINE(k, sub, n, o0, o1, o2) {".cfi_" #k, n, {Operand::kOpd##o0, Operand::kOpd##o1, Operand::kOpd##o2}},
1651 #define ARM_DIRECTIVES_DEFINE(k, sub, n, o0, o1, o2) \
1652     {"." #k, n, {Operand::kOpd##o0, Operand::kOpd##o1, Operand::kOpd##o2}},
1653 #include "cfi.def"
1654 #undef CFI_DEFINE
1655 #undef ARM_DIRECTIVES_DEFINE
1656     {".cfi_undef", 0, {Operand::kOpdUndef, Operand::kOpdUndef, Operand::kOpdUndef}}};
1657 
EmitAArch64CfiInsn(Emitter & emitter,const Insn & insn) const1658 void AArch64AsmEmitter::EmitAArch64CfiInsn(Emitter &emitter, const Insn &insn) const
1659 {
1660     MOperator mOp = insn.GetMachineOpcode();
1661     CfiDescr &cfiDescr = cfiDescrTable[mOp];
1662     (void)emitter.Emit("\t").Emit(cfiDescr.name);
1663     for (uint32 i = 0; i < cfiDescr.opndCount; ++i) {
1664         (void)emitter.Emit(" ");
1665         Operand &curOperand = insn.GetOperand(i);
1666         cfi::CFIOpndEmitVisitor cfiOpndEmitVisitor(emitter);
1667         curOperand.Accept(cfiOpndEmitVisitor);
1668         if (i < (cfiDescr.opndCount - 1)) {
1669             (void)emitter.Emit(",");
1670         }
1671     }
1672     (void)emitter.Emit("\n");
1673 }
1674 
1675 struct DbgDescr {
1676     const std::string name;
1677     uint32 opndCount;
1678     /* create 3 OperandType array to store dbg instruction's operand type */
1679     std::array<Operand::OperandType, 3> opndTypes;
1680 };
1681 
1682 static DbgDescr dbgDescrTable[mpldbg::kOpDbgLast + 1] = {
1683 #define DBG_DEFINE(k, sub, n, o0, o1, o2) {#k, n, {Operand::kOpd##o0, Operand::kOpd##o1, Operand::kOpd##o2}},
1684 #include "dbg.def"
1685 #undef DBG_DEFINE
1686     {"undef", 0, {Operand::kOpdUndef, Operand::kOpdUndef, Operand::kOpdUndef}}};
1687 
EmitAArch64DbgInsn(Emitter & emitter,const Insn & insn) const1688 void AArch64AsmEmitter::EmitAArch64DbgInsn(Emitter &emitter, const Insn &insn) const
1689 {
1690     MOperator mOp = insn.GetMachineOpcode();
1691     DbgDescr &dbgDescr = dbgDescrTable[mOp];
1692     (void)emitter.Emit("\t.").Emit(dbgDescr.name);
1693     for (uint32 i = 0; i < dbgDescr.opndCount; ++i) {
1694         (void)emitter.Emit(" ");
1695         Operand &curOperand = insn.GetOperand(i);
1696         mpldbg::DBGOpndEmitVisitor dbgOpndEmitVisitor(emitter);
1697         curOperand.Accept(dbgOpndEmitVisitor);
1698     }
1699     (void)emitter.Emit("\n");
1700 }
1701 
CheckInsnRefField(const Insn & insn,size_t opndIndex) const1702 bool AArch64AsmEmitter::CheckInsnRefField(const Insn &insn, size_t opndIndex) const
1703 {
1704     if (insn.IsAccessRefField() && insn.AccessMem()) {
1705         Operand &opnd0 = insn.GetOperand(opndIndex);
1706         if (opnd0.IsRegister()) {
1707             static_cast<RegOperand &>(opnd0).SetRefField(true);
1708             return true;
1709         }
1710     }
1711     return false;
1712 }
1713 } /* namespace maplebe */
1714