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 §ionName = 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