77 cl::desc(
"Check pointer authentication auth/resign failures"),
80#define DEBUG_TYPE "asm-printer"
88 bool ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags =
false;
91 AArch64AsmPrinter(
TargetMachine &
TM, std::unique_ptr<MCStreamer> Streamer)
92 :
AsmPrinter(
TM, std::move(Streamer)), MCInstLowering(OutContext, *
this),
112 const MCSymbol *BranchLabel)
const override;
133 void LowerPATCHABLE_EVENT_CALL(
const MachineInstr &
MI,
bool Typed);
135 typedef std::tuple<unsigned, bool, uint32_t, bool, uint64_t>
136 HwasanMemaccessTuple;
137 std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
140 void emitHwasanMemaccessSymbols(
Module &M);
151 unsigned emitPtrauthDiscriminator(
uint16_t Disc,
unsigned AddrDisc,
152 unsigned &InstsEmitted);
163 bool emitPseudoExpansionLowering(
MCStreamer &OutStreamer,
168 void emitFunctionHeaderComment()
override;
181 if (STI->isTargetCOFF()) {
234 using MInstToMCSymbol = std::map<const MachineInstr *, MCSymbol *>;
236 MInstToMCSymbol LOHInstToLabel;
239 return ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags;
254void AArch64AsmPrinter::emitStartOfAsmFile(
Module &M) {
257 if (
TT.isOSBinFormatCOFF()) {
260 OutStreamer->beginCOFFSymbolDef(S);
263 OutStreamer->endCOFFSymbolDef();
264 int64_t Feat00Value = 0;
266 if (
M.getModuleFlag(
"cfguard")) {
268 Feat00Value |= COFF::Feat00Flags::GuardCF;
271 if (
M.getModuleFlag(
"ehcontguard")) {
273 Feat00Value |= COFF::Feat00Flags::GuardEHCont;
276 if (
M.getModuleFlag(
"ms-kernel")) {
278 Feat00Value |= COFF::Feat00Flags::Kernel;
282 OutStreamer->emitAssignment(
286 if (!
TT.isOSBinFormatELF())
291 if (
const auto *BTE = mdconst::extract_or_null<ConstantInt>(
292 M.getModuleFlag(
"branch-target-enforcement")))
296 if (
const auto *GCS = mdconst::extract_or_null<ConstantInt>(
297 M.getModuleFlag(
"guarded-control-stack")))
301 if (
const auto *Sign = mdconst::extract_or_null<ConstantInt>(
302 M.getModuleFlag(
"sign-return-address")))
307 if (
const auto *PAP = mdconst::extract_or_null<ConstantInt>(
308 M.getModuleFlag(
"aarch64-elf-pauthabi-platform")))
309 PAuthABIPlatform = PAP->getZExtValue();
311 if (
const auto *PAV = mdconst::extract_or_null<ConstantInt>(
312 M.getModuleFlag(
"aarch64-elf-pauthabi-version")))
313 PAuthABIVersion = PAV->getZExtValue();
321void AArch64AsmPrinter::emitFunctionHeaderComment() {
324 if (OutlinerString != std::nullopt)
325 OutStreamer->getCommentOS() <<
' ' << OutlinerString;
328void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(
const MachineInstr &
MI)
331 if (
F.hasFnAttribute(
"patchable-function-entry")) {
333 if (
F.getFnAttribute(
"patchable-function-entry")
335 .getAsInteger(10, Num))
341 emitSled(
MI, SledKind::FUNCTION_ENTER);
344void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(
const MachineInstr &
MI) {
345 emitSled(
MI, SledKind::FUNCTION_EXIT);
348void AArch64AsmPrinter::LowerPATCHABLE_TAIL_CALL(
const MachineInstr &
MI) {
349 emitSled(
MI, SledKind::TAIL_CALL);
352void AArch64AsmPrinter::emitSled(
const MachineInstr &
MI, SledKind Kind) {
353 static const int8_t NoopsInSledCount = 7;
374 OutStreamer->emitCodeAlignment(
Align(4), &getSubtargetInfo());
375 auto CurSled = OutContext.createTempSymbol(
"xray_sled_",
true);
376 OutStreamer->emitLabel(CurSled);
377 auto Target = OutContext.createTempSymbol();
382 EmitToStreamer(*OutStreamer,
MCInstBuilder(AArch64::B).addImm(8));
384 for (int8_t
I = 0;
I < NoopsInSledCount;
I++)
385 EmitToStreamer(*OutStreamer,
MCInstBuilder(AArch64::HINT).addImm(0));
387 OutStreamer->emitLabel(
Target);
388 recordSled(CurSled,
MI, Kind, 2);
406void AArch64AsmPrinter::LowerPATCHABLE_EVENT_CALL(
const MachineInstr &
MI,
408 auto &
O = *OutStreamer;
409 MCSymbol *CurSled = OutContext.createTempSymbol(
"xray_sled_",
true);
410 O.emitLabel(CurSled);
421 bool MachO =
TM.getTargetTriple().isOSBinFormatMachO();
423 OutContext.getOrCreateSymbol(
424 Twine(MachO ?
"_" :
"") +
425 (Typed ?
"__xray_TypedEvent" :
"__xray_CustomEvent")),
428 O.AddComment(
"Begin XRay typed event");
440 EmitToStreamer(O, MovX0Op0);
441 EmitToStreamer(O, MovX1Op1);
444 .addReg(AArch64::XZR)
445 .addReg(
MI.getOperand(2).getReg())
452 O.AddComment(
"End XRay typed event");
460 recordSled(CurSled,
MI, SledKind::TYPED_EVENT, 2);
462 O.AddComment(
"Begin XRay custom event");
470 EmitToStreamer(O, MovX0Op0);
471 EmitToStreamer(O, MovX1Op1);
473 O.AddComment(
"End XRay custom event");
481 recordSled(CurSled,
MI, SledKind::CUSTOM_EVENT, 2);
487 assert(std::next(
MI.getIterator())->isCall() &&
488 "KCFI_CHECK not followed by a call instruction");
489 assert(std::next(
MI.getIterator())->getOperand(0).getReg() == AddrReg &&
490 "KCFI_CHECK call target doesn't match call operand");
494 unsigned ScratchRegs[] = {AArch64::W16, AArch64::W17};
495 if (AddrReg == AArch64::XZR) {
501 .addReg(AArch64::XZR)
502 .addReg(AArch64::XZR)
509 for (
auto &Reg : ScratchRegs) {
515 assert(ScratchRegs[0] != AddrReg && ScratchRegs[1] != AddrReg &&
516 "Invalid scratch registers for KCFI_CHECK");
520 int64_t PrefixNops = 0;
523 .getFnAttribute(
"patchable-function-prefix")
525 .getAsInteger(10, PrefixNops);
529 .addReg(ScratchRegs[0])
531 .addImm(-(PrefixNops * 4 + 4)));
535 const int64_t
Type =
MI.getOperand(1).getImm();
537 .addReg(ScratchRegs[1])
538 .addReg(ScratchRegs[1])
539 .addImm(
Type & 0xFFFF)
542 .addReg(ScratchRegs[1])
543 .addReg(ScratchRegs[1])
544 .addImm((
Type >> 16) & 0xFFFF)
549 .addReg(AArch64::WZR)
550 .addReg(ScratchRegs[0])
551 .addReg(ScratchRegs[1])
555 EmitToStreamer(*OutStreamer,
565 unsigned TypeIndex = ScratchRegs[1] - AArch64::W0;
569 AddrIndex = AddrReg - AArch64::X0;
579 assert(AddrIndex < 31 && TypeIndex < 31);
581 unsigned ESR = 0x8000 | ((TypeIndex & 31) << 5) | (AddrIndex & 31);
582 EmitToStreamer(*OutStreamer,
MCInstBuilder(AArch64::BRK).addImm(ESR));
583 OutStreamer->emitLabel(
Pass);
586void AArch64AsmPrinter::LowerHWASAN_CHECK_MEMACCESS(
const MachineInstr &
MI) {
589 ((
MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES) ||
591 AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
592 uint32_t AccessInfo =
MI.getOperand(1).getImm();
594 ((
MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW) ||
596 AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
597 uint64_t FixedShadowOffset = IsFixedShadow ?
MI.getOperand(2).getImm() : 0;
599 MCSymbol *&
Sym = HwasanMemaccessSymbols[HwasanMemaccessTuple(
600 Reg, IsShort, AccessInfo, IsFixedShadow, FixedShadowOffset)];
603 if (!
TM.getTargetTriple().isOSBinFormatELF())
606 std::string SymName =
"__hwasan_check_x" + utostr(Reg - AArch64::X0) +
"_" +
609 SymName +=
"_fixed_" + utostr(FixedShadowOffset);
611 SymName +=
"_short_v2";
612 Sym = OutContext.getOrCreateSymbol(SymName);
615 EmitToStreamer(*OutStreamer,
620void AArch64AsmPrinter::emitHwasanMemaccessSymbols(
Module &M) {
621 if (HwasanMemaccessSymbols.empty())
626 std::unique_ptr<MCSubtargetInfo> STI(
627 TM.getTarget().createMCSubtargetInfo(
TT.str(),
"",
""));
628 assert(STI &&
"Unable to create subtarget info");
631 OutContext.getOrCreateSymbol(
"__hwasan_tag_mismatch");
633 OutContext.getOrCreateSymbol(
"__hwasan_tag_mismatch_v2");
640 for (
auto &
P : HwasanMemaccessSymbols) {
641 unsigned Reg = std::get<0>(
P.first);
642 bool IsShort = std::get<1>(
P.first);
643 uint32_t AccessInfo = std::get<2>(
P.first);
644 bool IsFixedShadow = std::get<3>(
P.first);
645 uint64_t FixedShadowOffset = std::get<4>(
P.first);
647 IsShort ? HwasanTagMismatchV2Ref : HwasanTagMismatchV1Ref;
650 bool HasMatchAllTag =
652 uint8_t MatchAllTag =
659 OutStreamer->switchSection(OutContext.getELFSection(
667 OutStreamer->emitLabel(
Sym);
683 .
addImm(FixedShadowOffset >> 32)
686 OutStreamer->emitInstruction(
MCInstBuilder(AArch64::LDRBBroX)
694 OutStreamer->emitInstruction(
697 .
addReg(IsShort ? AArch64::X20 : AArch64::X9)
704 OutStreamer->emitInstruction(
711 MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
712 OutStreamer->emitInstruction(
718 MCSymbol *ReturnSym = OutContext.createTempSymbol();
719 OutStreamer->emitLabel(ReturnSym);
720 OutStreamer->emitInstruction(
722 OutStreamer->emitLabel(HandleMismatchOrPartialSym);
724 if (HasMatchAllTag) {
737 OutStreamer->emitInstruction(
751 MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
752 OutStreamer->emitInstruction(
758 OutStreamer->emitInstruction(
777 OutStreamer->emitInstruction(
783 OutStreamer->emitInstruction(
794 OutStreamer->emitInstruction(
801 OutStreamer->emitInstruction(
807 OutStreamer->emitLabel(HandleMismatchSym);
824 if (Reg != AArch64::X0)
831 OutStreamer->emitInstruction(
842 OutStreamer->emitInstruction(
848 OutStreamer->emitInstruction(
852 HwasanTagMismatchRef, AArch64MCExpr::VariantKind::VK_GOT_PAGE,
855 OutStreamer->emitInstruction(
860 HwasanTagMismatchRef, AArch64MCExpr::VariantKind::VK_GOT_LO12,
863 OutStreamer->emitInstruction(
871 const MCExpr *StubAuthPtrRef) {
874 OutStreamer.
emitValue(StubAuthPtrRef, 8);
877void AArch64AsmPrinter::emitEndOfAsmFile(
Module &M) {
878 emitHwasanMemaccessSymbols(M);
881 if (
TT.isOSBinFormatMachO()) {
888 if (!Stubs.empty()) {
890 OutStreamer->switchSection(
893 emitAlignment(
Align(8));
895 for (
const auto &Stub : Stubs)
898 OutStreamer->addBlankLine();
909 if (
TT.isOSBinFormatELF()) {
915 if (!Stubs.empty()) {
918 emitAlignment(
Align(8));
920 for (
const auto &Stub : Stubs)
923 OutStreamer->addBlankLine();
928 FM.serializeToFaultMapSection();
932void AArch64AsmPrinter::emitLOHs() {
935 for (
const auto &
D : AArch64FI->getLOHContainer()) {
937 MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(
MI);
938 assert(LabelIt != LOHInstToLabel.end() &&
939 "Label hasn't been inserted for LOH related instruction");
942 OutStreamer->emitLOHDirective(
D.getKind(), MCArgs);
947void AArch64AsmPrinter::emitFunctionBodyEnd() {
948 if (!AArch64FI->getLOHRelated().empty())
953MCSymbol *AArch64AsmPrinter::GetCPISymbol(
unsigned CPID)
const {
957 if (!getDataLayout().getLinkerPrivateGlobalPrefix().empty())
958 return OutContext.getOrCreateSymbol(
959 Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) +
"CPI" +
960 Twine(getFunctionNumber()) +
"_" +
Twine(CPID));
965void AArch64AsmPrinter::printOperand(
const MachineInstr *
MI,
unsigned OpNum,
983 PrintSymbolOperand(MO, O);
994bool AArch64AsmPrinter::printAsmMRegister(
const MachineOperand &MO,
char Mode,
1018bool AArch64AsmPrinter::printAsmRegInClass(
const MachineOperand &MO,
1021 assert(MO.
isReg() &&
"Should only get here with a register!");
1031bool AArch64AsmPrinter::PrintAsmOperand(
const MachineInstr *
MI,
unsigned OpNum,
1040 if (ExtraCode && ExtraCode[0]) {
1041 if (ExtraCode[1] != 0)
1044 switch (ExtraCode[0]) {
1052 unsigned Reg = ExtraCode[0] ==
'w' ? AArch64::WZR : AArch64::XZR;
1066 switch (ExtraCode[0]) {
1068 RC = &AArch64::FPR8RegClass;
1071 RC = &AArch64::FPR16RegClass;
1074 RC = &AArch64::FPR32RegClass;
1077 RC = &AArch64::FPR64RegClass;
1080 RC = &AArch64::FPR128RegClass;
1083 RC = &AArch64::ZPRRegClass;
1088 return printAsmRegInClass(MO, RC, AArch64::NoRegAltName, O);
1101 if (AArch64::GPR32allRegClass.
contains(Reg) ||
1102 AArch64::GPR64allRegClass.
contains(Reg))
1106 if (AArch64::GPR64x8ClassRegClass.
contains(Reg))
1109 unsigned AltName = AArch64::NoRegAltName;
1111 if (AArch64::ZPRRegClass.
contains(Reg)) {
1112 RegClass = &AArch64::ZPRRegClass;
1113 }
else if (AArch64::PPRRegClass.
contains(Reg)) {
1114 RegClass = &AArch64::PPRRegClass;
1115 }
else if (AArch64::PNRRegClass.
contains(Reg)) {
1116 RegClass = &AArch64::PNRRegClass;
1118 RegClass = &AArch64::FPR128RegClass;
1119 AltName = AArch64::vreg;
1123 return printAsmRegInClass(MO, RegClass, AltName, O);
1130bool AArch64AsmPrinter::PrintAsmMemoryOperand(
const MachineInstr *
MI,
1132 const char *ExtraCode,
1134 if (ExtraCode && ExtraCode[0] && ExtraCode[0] !=
'a')
1138 assert(MO.
isReg() &&
"unexpected inline asm memory operand");
1143void AArch64AsmPrinter::PrintDebugValueComment(
const MachineInstr *
MI,
1145 unsigned NOps =
MI->getNumOperands();
1147 OS <<
'\t' << MAI->getCommentString() <<
"DEBUG_VALUE: ";
1149 OS <<
MI->getDebugVariable()->getName();
1152 assert(
MI->isIndirectDebugValue());
1154 for (
unsigned I = 0, E = std::distance(
MI->debug_operands().begin(),
1155 MI->debug_operands().end());
1166void AArch64AsmPrinter::emitJumpTableInfo() {
1171 if (
JT.empty())
return;
1175 OutStreamer->switchSection(ReadOnlySec);
1178 for (
unsigned JTI = 0, e =
JT.size(); JTI !=
e; ++JTI) {
1179 const std::vector<MachineBasicBlock*> &JTBBs =
JT[JTI].MBBs;
1182 if (JTBBs.empty())
continue;
1184 unsigned Size = AFI->getJumpTableEntrySize(JTI);
1186 OutStreamer->emitLabel(GetJTISymbol(JTI));
1188 const MCSymbol *BaseSym = AArch64FI->getJumpTableEntryPCRelSymbol(JTI);
1191 for (
auto *JTBB : JTBBs) {
1211AArch64AsmPrinter::getCodeViewJumpTableInfo(
int JTI,
1213 const MCSymbol *BranchLabel)
const {
1215 const auto Base = AArch64FI->getJumpTableEntryPCRelSymbol(JTI);
1217 switch (AFI->getJumpTableEntrySize(JTI)) {
1219 EntrySize = codeview::JumpTableEntrySize::UInt8ShiftLeft;
1222 EntrySize = codeview::JumpTableEntrySize::UInt16ShiftLeft;
1225 EntrySize = codeview::JumpTableEntrySize::Int32;
1230 return std::make_tuple(
Base, 0, BranchLabel, EntrySize);
1233void AArch64AsmPrinter::emitFunctionEntryLabel() {
1235 MF->getFunction().getCallingConv() ==
1245 if (
TM.getTargetTriple().isWindowsArm64EC() &&
1246 !MF->getFunction().hasLocalLinkage()) {
1251 OutStreamer->emitAssignment(
1253 MMI->getContext()));
1259 StringRef NameStr = cast<MDString>(
Node->getOperand(0))->getString();
1260 Sym = MMI->getContext().getOrCreateSymbol(NameStr);
1266 getSymbolFromMetadata(
"arm64ec_unmangled_name")) {
1267 MCSymbol *ECMangledSym = getSymbolFromMetadata(
"arm64ec_ecmangled_name");
1273 emitFunctionAlias(UnmangledSym, ECMangledSym);
1274 emitFunctionAlias(ECMangledSym, CurrentFnSym);
1278 emitFunctionAlias(UnmangledSym, CurrentFnSym);
1284void AArch64AsmPrinter::emitGlobalAlias(
const Module &M,
1286 if (
auto F = dyn_cast_or_null<Function>(GA.
getAliasee())) {
1291 if (
MDNode *
Node =
F->getMetadata(
"arm64ec_exp_name")) {
1292 StringRef ExpStr = cast<MDString>(
Node->getOperand(0))->getString();
1293 MCSymbol *ExpSym = MMI->getContext().getOrCreateSymbol(ExpStr);
1295 OutStreamer->beginCOFFSymbolDef(
Sym);
1299 OutStreamer->endCOFFSymbolDef();
1301 OutStreamer->emitAssignment(
1303 MMI->getContext()));
1321 Register DestReg =
MI.getOperand(0).getReg();
1322 Register ScratchReg =
MI.getOperand(1).getReg();
1324 STI->getRegisterInfo()->getSubReg(ScratchReg, AArch64::sub_32);
1325 Register TableReg =
MI.getOperand(2).getReg();
1326 Register EntryReg =
MI.getOperand(3).getReg();
1327 int JTIdx =
MI.getOperand(4).getIndex();
1328 int Size = AArch64FI->getJumpTableEntrySize(JTIdx);
1338 Label = MF->getContext().createTempSymbol();
1339 AArch64FI->setJumpTableEntryInfo(JTIdx,
Size, Label);
1346 .addExpr(LabelExpr));
1351 case 1: LdrOpcode = AArch64::LDRBBroX;
break;
1352 case 2: LdrOpcode = AArch64::LDRHHroX;
break;
1353 case 4: LdrOpcode = AArch64::LDRSWroX;
break;
1359 .addReg(
Size == 4 ? ScratchReg : ScratchRegW)
1363 .addImm(
Size == 1 ? 0 : 1));
1371 .addImm(
Size == 4 ? 0 : 2));
1374void AArch64AsmPrinter::LowerHardenedBRJumpTable(
const MachineInstr &
MI) {
1375 unsigned InstsEmitted = 0;
1378 assert(MJTI &&
"Can't lower jump-table dispatch without JTI");
1380 const std::vector<MachineJumpTableEntry> &JTs = MJTI->
getJumpTables();
1381 assert(!JTs.empty() &&
"Invalid JT index for jump-table dispatch");
1400 assert(!AArch64FI->getJumpTableEntryPCRelSymbol(JTI) &&
1401 "unsupported compressed jump table");
1403 const uint64_t NumTableEntries = JTs[JTI].MBBs.size();
1407 uint64_t MaxTableEntry = NumTableEntries - 1;
1408 if (isUInt<12>(MaxTableEntry)) {
1409 EmitToStreamer(*OutStreamer,
MCInstBuilder(AArch64::SUBSXri)
1410 .addReg(AArch64::XZR)
1411 .addReg(AArch64::X16)
1412 .addImm(MaxTableEntry)
1416 EmitToStreamer(*OutStreamer,
1418 .addReg(AArch64::X17)
1419 .addImm(
static_cast<uint16_t>(MaxTableEntry))
1426 if ((MaxTableEntry >>
Offset) == 0)
1428 EmitToStreamer(*OutStreamer,
1430 .addReg(AArch64::X17)
1431 .addReg(AArch64::X17)
1436 EmitToStreamer(*OutStreamer,
MCInstBuilder(AArch64::SUBSXrs)
1437 .addReg(AArch64::XZR)
1438 .addReg(AArch64::X16)
1439 .addReg(AArch64::X17)
1447 .addReg(AArch64::X16)
1448 .addReg(AArch64::X16)
1449 .addReg(AArch64::XZR)
1460 MCInstLowering.lowerOperand(JTMOHi, JTMCHi);
1461 MCInstLowering.lowerOperand(JTMOLo, JTMCLo);
1469 .addReg(AArch64::X17)
1470 .addReg(AArch64::X17)
1475 EmitToStreamer(*OutStreamer,
MCInstBuilder(AArch64::LDRSWroX)
1476 .addReg(AArch64::X16)
1477 .addReg(AArch64::X17)
1478 .addReg(AArch64::X16)
1483 MCSymbol *AdrLabel = MF->getContext().createTempSymbol();
1485 AArch64FI->setJumpTableEntryInfo(JTI, 4, AdrLabel);
1490 MCInstBuilder(AArch64::ADR).addReg(AArch64::X17).addExpr(AdrLabelE));
1494 .addReg(AArch64::X16)
1495 .addReg(AArch64::X17)
1496 .addReg(AArch64::X16)
1500 EmitToStreamer(*OutStreamer,
MCInstBuilder(AArch64::BR).addReg(AArch64::X16));
1504 assert(STI->getInstrInfo()->getInstSizeInBytes(
MI) >= InstsEmitted * 4);
1509 unsigned Opcode =
MI.getOpcode();
1511 assert(STI->hasMTE() || Opcode != AArch64::MOPSMemorySetTaggingPseudo);
1513 const auto Ops = [Opcode]() -> std::array<unsigned, 3> {
1514 if (Opcode == AArch64::MOPSMemoryCopyPseudo)
1515 return {AArch64::CPYFP, AArch64::CPYFM, AArch64::CPYFE};
1516 if (Opcode == AArch64::MOPSMemoryMovePseudo)
1517 return {AArch64::CPYP, AArch64::CPYM, AArch64::CPYE};
1518 if (Opcode == AArch64::MOPSMemorySetPseudo)
1519 return {AArch64::SETP, AArch64::SETM, AArch64::SETE};
1520 if (Opcode == AArch64::MOPSMemorySetTaggingPseudo)
1521 return {AArch64::SETGP, AArch64::SETGM, AArch64::MOPSSETGE};
1524 const bool IsSet = Opcode == AArch64::MOPSMemorySetPseudo ||
1525 Opcode == AArch64::MOPSMemorySetTaggingPseudo;
1527 for (
auto Op : Ops) {
1531 MCIB.addReg(
MI.getOperand(i++).getReg());
1532 MCIB.addReg(
MI.getOperand(i++).getReg());
1534 MCIB.addReg(
MI.getOperand(i++).getReg());
1536 MCIB.addReg(
MI.getOperand(i++).getReg());
1537 MCIB.addReg(
MI.getOperand(i++).getReg());
1538 MCIB.addReg(
MI.getOperand(i++).getReg());
1540 EmitToStreamer(OutStreamer, MCIB);
1549 MCSymbol *MILabel = Ctx.createTempSymbol();
1553 assert(NumNOPBytes % 4 == 0 &&
"Invalid number of NOP bytes requested!");
1559 while (NumNOPBytes > 0) {
1560 if (MII ==
MBB.
end() || MII->isCall() ||
1561 MII->getOpcode() == AArch64::DBG_VALUE ||
1562 MII->getOpcode() == TargetOpcode::PATCHPOINT ||
1563 MII->getOpcode() == TargetOpcode::STACKMAP)
1570 for (
unsigned i = 0; i < NumNOPBytes; i += 4)
1571 EmitToStreamer(OutStreamer,
MCInstBuilder(AArch64::HINT).addImm(0));
1579 MCSymbol *MILabel = Ctx.createTempSymbol();
1585 int64_t CallTarget = Opers.getCallTarget().getImm();
1586 unsigned EncodedBytes = 0;
1588 assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
1589 "High 16 bits of call target should be zero.");
1590 Register ScratchReg =
MI.getOperand(Opers.getNextScratchIdx()).getReg();
1595 .addImm((CallTarget >> 32) & 0xFFFF)
1600 .addImm((CallTarget >> 16) & 0xFFFF)
1605 .addImm(CallTarget & 0xFFFF)
1607 EmitToStreamer(OutStreamer,
MCInstBuilder(AArch64::BLR).addReg(ScratchReg));
1610 unsigned NumBytes = Opers.getNumPatchBytes();
1611 assert(NumBytes >= EncodedBytes &&
1612 "Patchpoint can't request size less than the length of a call.");
1613 assert((NumBytes - EncodedBytes) % 4 == 0 &&
1614 "Invalid number of NOP bytes requested!");
1615 for (
unsigned i = EncodedBytes; i < NumBytes; i += 4)
1616 EmitToStreamer(OutStreamer,
MCInstBuilder(AArch64::HINT).addImm(0));
1622 if (
unsigned PatchBytes = SOpers.getNumPatchBytes()) {
1623 assert(PatchBytes % 4 == 0 &&
"Invalid number of NOP bytes requested!");
1624 for (
unsigned i = 0; i < PatchBytes; i += 4)
1625 EmitToStreamer(OutStreamer,
MCInstBuilder(AArch64::HINT).addImm(0));
1630 unsigned CallOpcode;
1631 switch (CallTarget.
getType()) {
1634 MCInstLowering.lowerOperand(CallTarget, CallTargetMCOp);
1635 CallOpcode = AArch64::BL;
1639 CallOpcode = AArch64::BL;
1643 CallOpcode = AArch64::BLR;
1650 EmitToStreamer(OutStreamer,
1655 MCSymbol *MILabel = Ctx.createTempSymbol();
1660void AArch64AsmPrinter::LowerFAULTING_OP(
const MachineInstr &FaultingMI) {
1669 unsigned OperandsBeginIdx = 4;
1672 MCSymbol *FaultingLabel = Ctx.createTempSymbol();
1676 FM.recordFaultingOp(FK, FaultingLabel, HandlerLabel);
1679 MI.setOpcode(Opcode);
1687 lowerOperand(MO, Dest);
1688 MI.addOperand(Dest);
1696 Register DestReg =
MI.getOperand(0).getReg();
1697 if (STI->hasZeroCycleZeroingFP() && !STI->hasZeroCycleZeroingFPWorkaround() &&
1698 STI->isNeonAvailable()) {
1700 if (AArch64::H0 <= DestReg && DestReg <= AArch64::H31)
1701 DestReg = AArch64::D0 + (DestReg - AArch64::H0);
1702 else if (AArch64::S0 <= DestReg && DestReg <= AArch64::S31)
1703 DestReg = AArch64::D0 + (DestReg - AArch64::S0);
1705 assert(AArch64::D0 <= DestReg && DestReg <= AArch64::D31);
1708 MOVI.setOpcode(AArch64::MOVID);
1711 EmitToStreamer(*OutStreamer, MOVI);
1714 switch (
MI.getOpcode()) {
1716 case AArch64::FMOVH0:
1717 FMov.
setOpcode(STI->hasFullFP16() ? AArch64::FMOVWHr : AArch64::FMOVWSr);
1718 if (!STI->hasFullFP16())
1719 DestReg = (AArch64::S0 + (DestReg - AArch64::H0));
1723 case AArch64::FMOVS0:
1728 case AArch64::FMOVD0:
1734 EmitToStreamer(*OutStreamer, FMov);
1738unsigned AArch64AsmPrinter::emitPtrauthDiscriminator(
uint16_t Disc,
1740 unsigned &InstsEmitted) {
1742 if (AddrDisc == AArch64::NoRegister)
1743 AddrDisc = AArch64::XZR;
1751 if (AddrDisc == AArch64::XZR) {
1753 .addReg(AArch64::X17)
1757 return AArch64::X17;
1762 .addReg(AArch64::X17)
1763 .addReg(AArch64::XZR)
1768 .addReg(AArch64::X17)
1769 .addReg(AArch64::X17)
1773 return AArch64::X17;
1776void AArch64AsmPrinter::emitPtrauthAuthResign(
const MachineInstr *
MI) {
1777 unsigned InstsEmitted = 0;
1778 const bool IsAUTPAC =
MI->getOpcode() == AArch64::AUTPAC;
1829 bool ShouldCheck =
true;
1831 bool ShouldTrap = MF->getFunction().hasFnAttribute(
"ptrauth-auth-traps");
1836 ShouldCheck = ShouldTrap =
false;
1843 ShouldCheck = ShouldTrap =
false;
1850 ShouldCheck = ShouldTrap =
true;
1855 uint64_t AUTDisc =
MI->getOperand(1).getImm();
1856 unsigned AUTAddrDisc =
MI->getOperand(2).getReg();
1861 assert(isUInt<16>(AUTDisc));
1862 unsigned AUTDiscReg =
1863 emitPtrauthDiscriminator(AUTDisc, AUTAddrDisc, InstsEmitted);
1864 bool AUTZero = AUTDiscReg == AArch64::XZR;
1875 EmitToStreamer(*OutStreamer, AUTInst);
1879 if (!IsAUTPAC && (!ShouldCheck || !ShouldTrap)) {
1880 assert(STI->getInstrInfo()->getInstSizeInBytes(*
MI) >= InstsEmitted * 4);
1888 MCSymbol *SuccessSym = createTempSymbol(
"auth_success_");
1893 .addReg(AArch64::X17)
1894 .addReg(AArch64::XZR)
1895 .addReg(AArch64::X16)
1902 MCInstBuilder(XPACOpc).addReg(AArch64::X17).addReg(AArch64::X17));
1906 EmitToStreamer(*OutStreamer,
MCInstBuilder(AArch64::SUBSXrs)
1907 .addReg(AArch64::XZR)
1908 .addReg(AArch64::X16)
1909 .addReg(AArch64::X17)
1917 SuccessSym, OutContext)));
1923 EmitToStreamer(*OutStreamer,
1934 .addReg(AArch64::X16)
1935 .addReg(AArch64::XZR)
1936 .addReg(AArch64::X17)
1941 EndSym = createTempSymbol(
"resign_end_");
1946 EndSym, OutContext)));
1960 assert(STI->getInstrInfo()->getInstSizeInBytes(*
MI) >= InstsEmitted * 4);
1965 uint64_t PACDisc =
MI->getOperand(4).getImm();
1966 unsigned PACAddrDisc =
MI->getOperand(5).getReg();
1969 assert(isUInt<16>(PACDisc));
1970 unsigned PACDiscReg =
1971 emitPtrauthDiscriminator(PACDisc, PACAddrDisc, InstsEmitted);
1972 bool PACZero = PACDiscReg == AArch64::XZR;
1983 EmitToStreamer(*OutStreamer, PACInst);
1986 assert(STI->getInstrInfo()->getInstSizeInBytes(*
MI) >= InstsEmitted * 4);
1992void AArch64AsmPrinter::emitPtrauthBranch(
const MachineInstr *
MI) {
1993 unsigned InstsEmitted = 0;
1994 bool IsCall =
MI->getOpcode() == AArch64::BLRA;
1995 unsigned BrTarget =
MI->getOperand(0).getReg();
1999 "Invalid auth call key");
2002 assert(isUInt<16>(Disc));
2004 unsigned AddrDisc =
MI->getOperand(3).getReg();
2007 unsigned DiscReg = emitPtrauthDiscriminator(Disc, AddrDisc, InstsEmitted);
2008 bool IsZeroDisc = DiscReg == AArch64::XZR;
2013 Opc = IsZeroDisc ? AArch64::BLRAAZ : AArch64::BLRAA;
2015 Opc = IsZeroDisc ? AArch64::BLRABZ : AArch64::BLRAB;
2018 Opc = IsZeroDisc ? AArch64::BRAAZ : AArch64::BRAA;
2020 Opc = IsZeroDisc ? AArch64::BRABZ : AArch64::BRAB;
2028 EmitToStreamer(*OutStreamer, BRInst);
2031 assert(STI->getInstrInfo()->getInstSizeInBytes(*
MI) >= InstsEmitted * 4);
2041 getDataLayout(),
Offset,
true);
2043 auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);
2049 "cannot resolve target base/addend of ptrauth constant");
2067 "' out of range [0, " +
2071 if (!isUInt<16>(Disc))
2073 "' out of range [0, 0xFFFF]");
2080void AArch64AsmPrinter::LowerLOADauthptrstatic(
const MachineInstr &
MI) {
2081 unsigned DstReg =
MI.getOperand(0).getReg();
2083 const uint64_t KeyC =
MI.getOperand(2).getImm();
2085 "key is out of range [0, AArch64PACKey::LAST]");
2087 const uint64_t Disc =
MI.getOperand(3).getImm();
2088 assert(isUInt<16>(Disc) &&
2089 "constant discriminator is out of range [0, 0xffff]");
2098 if (
TM.getTargetTriple().isOSBinFormatELF()) {
2103 "non-zero offset for $auth_ptr$ stub slots is not supported");
2105 AuthPtrStubSym = TLOF.getAuthPtrSlotSymbol(
TM, MMI, GASym, Key, Disc);
2107 assert(
TM.getTargetTriple().isOSBinFormatMachO() &&
2108 "LOADauthptrstatic is implemented only for MachO/ELF");
2111 getObjFileLowering());
2114 "non-zero offset for $auth_ptr$ stub slots is not supported");
2116 AuthPtrStubSym = TLOF.getAuthPtrSlotSymbol(
TM, MMI, GASym, Key, Disc);
2125 MCInstLowering.lowerOperand(StubMOHi, StubMCHi);
2126 MCInstLowering.lowerOperand(StubMOLo, StubMCLo);
2139 unsigned InstsEmitted = 0;
2140 auto EmitAndIncrement = [
this, &InstsEmitted](
const MCInst &Inst) {
2141 EmitToStreamer(*OutStreamer, Inst);
2145 const bool IsGOTLoad =
MI.getOpcode() == AArch64::LOADgotPAC;
2147 const uint64_t KeyC =
MI.getOperand(1).getImm();
2149 "key is out of range [0, AArch64PACKey::LAST]");
2151 const unsigned AddrDisc =
MI.getOperand(2).getReg();
2152 const uint64_t Disc =
MI.getOperand(3).getImm();
2153 assert(isUInt<16>(Disc) &&
2154 "constant discriminator is out of range [0, 0xffff]");
2203 MCInstLowering.lowerOperand(GAMOHi, GAMCHi);
2204 MCInstLowering.lowerOperand(GAMOLo, GAMCLo);
2211 .addReg(AArch64::X16)
2212 .addReg(AArch64::X16)
2216 .addReg(AArch64::X16)
2217 .addReg(AArch64::X16)
2224 const bool IsNeg =
Offset < 0;
2225 if (isUInt<24>(AbsOffset)) {
2226 for (
int BitPos = 0; BitPos != 24 && (AbsOffset >> BitPos);
2230 .addReg(AArch64::X16)
2231 .addReg(AArch64::X16)
2232 .addImm((AbsOffset >> BitPos) & 0xfff)
2237 EmitAndIncrement(
MCInstBuilder(IsNeg ? AArch64::MOVNXi : AArch64::MOVZXi)
2238 .addReg(AArch64::X17)
2239 .addImm((IsNeg ? ~UOffset : UOffset) & 0xffff)
2241 auto NeedMovk = [IsNeg, UOffset](
int BitPos) ->
bool {
2242 assert(BitPos == 16 || BitPos == 32 || BitPos == 48);
2243 uint64_t Shifted = UOffset >> BitPos;
2245 return Shifted != 0;
2246 for (
int I = 0;
I != 64 - BitPos;
I += 16)
2247 if (((Shifted >>
I) & 0xffff) != 0xffff)
2251 for (
int BitPos = 16; BitPos != 64 && NeedMovk(BitPos); BitPos += 16) {
2253 .addReg(AArch64::X17)
2254 .addReg(AArch64::X17)
2255 .addImm((UOffset >> BitPos) & 0xffff)
2259 .addReg(AArch64::X16)
2260 .addReg(AArch64::X16)
2261 .addReg(AArch64::X17)
2266 unsigned DiscReg = AddrDisc;
2268 if (AddrDisc != AArch64::XZR) {
2270 .addReg(AArch64::X17)
2271 .addReg(AArch64::XZR)
2275 .addReg(AArch64::X17)
2276 .addReg(AArch64::X17)
2281 .addReg(AArch64::X17)
2285 DiscReg = AArch64::X17;
2291 if (DiscReg != AArch64::XZR)
2293 EmitAndIncrement(MIB);
2295 assert(STI->getInstrInfo()->getInstSizeInBytes(
MI) >= InstsEmitted * 4);
2299AArch64AsmPrinter::lowerBlockAddressConstant(
const BlockAddress &BA) {
2303 if (std::optional<uint16_t> BADisc =
2304 STI->getPtrAuthBlockAddressDiscriminatorIfEnabled(Fn))
2313#include "AArch64GenMCPseudoLowering.inc"
2316 AArch64_MC::verifyInstructionPredicates(
MI->getOpcode(), STI->getFeatureBits());
2319 if (emitPseudoExpansionLowering(*OutStreamer,
MI))
2322 if (
MI->getOpcode() == AArch64::ADRP) {
2323 for (
auto &Opd :
MI->operands()) {
2324 if (Opd.isSymbol() &&
StringRef(Opd.getSymbolName()) ==
2325 "swift_async_extendedFramePointerFlags") {
2326 ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags =
true;
2331 if (AArch64FI->getLOHRelated().count(
MI)) {
2333 MCSymbol *LOHLabel = createTempSymbol(
"loh");
2335 LOHInstToLabel[
MI] = LOHLabel;
2342 switch (
MI->getOpcode()) {
2345 case AArch64::HINT: {
2350 if (CurrentPatchableFunctionEntrySym &&
2351 CurrentPatchableFunctionEntrySym == CurrentFnBegin &&
2352 MI == &MF->front().front()) {
2353 int64_t
Imm =
MI->getOperand(0).getImm();
2354 if ((Imm & 32) && (
Imm & 6)) {
2356 MCInstLowering.Lower(
MI, Inst);
2357 EmitToStreamer(*OutStreamer, Inst);
2358 CurrentPatchableFunctionEntrySym = createTempSymbol(
"patch");
2359 OutStreamer->
emitLabel(CurrentPatchableFunctionEntrySym);
2365 case AArch64::MOVMCSym: {
2366 Register DestReg =
MI->getOperand(0).getReg();
2374 MCInstLowering.lowerOperand(Hi_MOSym, Hi_MCSym);
2375 MCInstLowering.lowerOperand(Lo_MOSym, Lo_MCSym);
2382 EmitToStreamer(*OutStreamer, MovZ);
2390 EmitToStreamer(*OutStreamer, MovK);
2393 case AArch64::MOVIv2d_ns:
2401 if (STI->hasZeroCycleZeroingFPWorkaround() &&
2402 MI->getOperand(1).getImm() == 0) {
2404 TmpInst.
setOpcode(AArch64::MOVIv16b_ns);
2407 EmitToStreamer(*OutStreamer, TmpInst);
2412 case AArch64::DBG_VALUE:
2413 case AArch64::DBG_VALUE_LIST:
2417 PrintDebugValueComment(
MI,
OS);
2422 case AArch64::EMITBKEY: {
2424 if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
2425 ExceptionHandlingType != ExceptionHandling::ARM)
2428 if (getFunctionCFISectionType(*MF) == CFISection::None)
2435 case AArch64::EMITMTETAGGED: {
2437 if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
2438 ExceptionHandlingType != ExceptionHandling::ARM)
2441 if (getFunctionCFISectionType(*MF) != CFISection::None)
2447 case AArch64::AUTPAC:
2448 emitPtrauthAuthResign(
MI);
2451 case AArch64::LOADauthptrstatic:
2452 LowerLOADauthptrstatic(*
MI);
2455 case AArch64::LOADgotPAC:
2456 case AArch64::MOVaddrPAC:
2457 LowerMOVaddrPAC(*
MI);
2462 emitPtrauthBranch(
MI);
2468 case AArch64::AUTH_TCRETURN:
2469 case AArch64::AUTH_TCRETURN_BTI: {
2472 "Invalid auth key for tail-call return");
2474 const uint64_t Disc =
MI->getOperand(3).getImm();
2475 assert(isUInt<16>(Disc) &&
"Integer discriminator is too wide");
2477 Register AddrDisc =
MI->getOperand(4).getReg();
2479 Register ScratchReg =
MI->getOperand(0).getReg() == AArch64::X16
2483 unsigned DiscReg = AddrDisc;
2485 if (AddrDisc != AArch64::NoRegister) {
2488 .addReg(AArch64::XZR)
2502 DiscReg = ScratchReg;
2505 const bool IsZero = DiscReg == AArch64::NoRegister;
2506 const unsigned Opcodes[2][2] = {{AArch64::BRAA, AArch64::BRAAZ},
2507 {AArch64::BRAB, AArch64::BRABZ}};
2510 TmpInst.
setOpcode(Opcodes[Key][IsZero]);
2514 EmitToStreamer(*OutStreamer, TmpInst);
2518 case AArch64::TCRETURNri:
2519 case AArch64::TCRETURNrix16x17:
2520 case AArch64::TCRETURNrix17:
2521 case AArch64::TCRETURNrinotx16:
2522 case AArch64::TCRETURNriALL: {
2526 EmitToStreamer(*OutStreamer, TmpInst);
2529 case AArch64::TCRETURNdi: {
2531 MCInstLowering.lowerOperand(
MI->getOperand(0), Dest);
2535 EmitToStreamer(*OutStreamer, TmpInst);
2538 case AArch64::SpeculationBarrierISBDSBEndBB: {
2543 EmitToStreamer(*OutStreamer, TmpInstDSB);
2547 EmitToStreamer(*OutStreamer, TmpInstISB);
2550 case AArch64::SpeculationBarrierSBEndBB: {
2554 EmitToStreamer(*OutStreamer, TmpInstSB);
2557 case AArch64::TLSDESC_CALLSEQ: {
2570 MCInstLowering.lowerOperand(MO_Sym,
Sym);
2571 MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
2572 MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);
2578 EmitToStreamer(*OutStreamer, Adrp);
2581 if (STI->isTargetILP32()) {
2591 EmitToStreamer(*OutStreamer, Ldr);
2594 if (STI->isTargetILP32()) {
2595 Add.setOpcode(AArch64::ADDWri);
2599 Add.setOpcode(AArch64::ADDXri);
2603 Add.addOperand(SymTLSDescLo12);
2605 EmitToStreamer(*OutStreamer,
Add);
2610 TLSDescCall.
setOpcode(AArch64::TLSDESCCALL);
2612 EmitToStreamer(*OutStreamer, TLSDescCall);
2617 EmitToStreamer(*OutStreamer, Blr);
2622 case AArch64::JumpTableDest32:
2623 case AArch64::JumpTableDest16:
2624 case AArch64::JumpTableDest8:
2625 LowerJumpTableDest(*OutStreamer, *
MI);
2628 case AArch64::BR_JumpTable:
2629 LowerHardenedBRJumpTable(*
MI);
2632 case AArch64::FMOVH0:
2633 case AArch64::FMOVS0:
2634 case AArch64::FMOVD0:
2638 case AArch64::MOPSMemoryCopyPseudo:
2639 case AArch64::MOPSMemoryMovePseudo:
2640 case AArch64::MOPSMemorySetPseudo:
2641 case AArch64::MOPSMemorySetTaggingPseudo:
2642 LowerMOPS(*OutStreamer, *
MI);
2645 case TargetOpcode::STACKMAP:
2646 return LowerSTACKMAP(*OutStreamer, SM, *
MI);
2648 case TargetOpcode::PATCHPOINT:
2649 return LowerPATCHPOINT(*OutStreamer, SM, *
MI);
2651 case TargetOpcode::STATEPOINT:
2652 return LowerSTATEPOINT(*OutStreamer, SM, *
MI);
2654 case TargetOpcode::FAULTING_OP:
2655 return LowerFAULTING_OP(*
MI);
2657 case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
2658 LowerPATCHABLE_FUNCTION_ENTER(*
MI);
2661 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
2662 LowerPATCHABLE_FUNCTION_EXIT(*
MI);
2665 case TargetOpcode::PATCHABLE_TAIL_CALL:
2666 LowerPATCHABLE_TAIL_CALL(*
MI);
2668 case TargetOpcode::PATCHABLE_EVENT_CALL:
2669 return LowerPATCHABLE_EVENT_CALL(*
MI,
false);
2670 case TargetOpcode::PATCHABLE_TYPED_EVENT_CALL:
2671 return LowerPATCHABLE_EVENT_CALL(*
MI,
true);
2673 case AArch64::KCFI_CHECK:
2674 LowerKCFI_CHECK(*
MI);
2677 case AArch64::HWASAN_CHECK_MEMACCESS:
2678 case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
2679 case AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW:
2680 case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW:
2681 LowerHWASAN_CHECK_MEMACCESS(*
MI);
2684 case AArch64::SEH_StackAlloc:
2688 case AArch64::SEH_SaveFPLR:
2692 case AArch64::SEH_SaveFPLR_X:
2693 assert(
MI->getOperand(0).getImm() < 0 &&
2694 "Pre increment SEH opcode must have a negative offset");
2698 case AArch64::SEH_SaveReg:
2700 MI->getOperand(1).getImm());
2703 case AArch64::SEH_SaveReg_X:
2704 assert(
MI->getOperand(1).getImm() < 0 &&
2705 "Pre increment SEH opcode must have a negative offset");
2707 -
MI->getOperand(1).getImm());
2710 case AArch64::SEH_SaveRegP:
2711 if (
MI->getOperand(1).getImm() == 30 &&
MI->getOperand(0).getImm() >= 19 &&
2712 MI->getOperand(0).getImm() <= 28) {
2713 assert((
MI->getOperand(0).getImm() - 19) % 2 == 0 &&
2714 "Register paired with LR must be odd");
2716 MI->getOperand(2).getImm());
2719 assert((
MI->getOperand(1).getImm() -
MI->getOperand(0).getImm() == 1) &&
2720 "Non-consecutive registers not allowed for save_regp");
2722 MI->getOperand(2).getImm());
2725 case AArch64::SEH_SaveRegP_X:
2726 assert((
MI->getOperand(1).getImm() -
MI->getOperand(0).getImm() == 1) &&
2727 "Non-consecutive registers not allowed for save_regp_x");
2728 assert(
MI->getOperand(2).getImm() < 0 &&
2729 "Pre increment SEH opcode must have a negative offset");
2731 -
MI->getOperand(2).getImm());
2734 case AArch64::SEH_SaveFReg:
2736 MI->getOperand(1).getImm());
2739 case AArch64::SEH_SaveFReg_X:
2740 assert(
MI->getOperand(1).getImm() < 0 &&
2741 "Pre increment SEH opcode must have a negative offset");
2743 -
MI->getOperand(1).getImm());
2746 case AArch64::SEH_SaveFRegP:
2747 assert((
MI->getOperand(1).getImm() -
MI->getOperand(0).getImm() == 1) &&
2748 "Non-consecutive registers not allowed for save_regp");
2750 MI->getOperand(2).getImm());
2753 case AArch64::SEH_SaveFRegP_X:
2754 assert((
MI->getOperand(1).getImm() -
MI->getOperand(0).getImm() == 1) &&
2755 "Non-consecutive registers not allowed for save_regp_x");
2756 assert(
MI->getOperand(2).getImm() < 0 &&
2757 "Pre increment SEH opcode must have a negative offset");
2759 -
MI->getOperand(2).getImm());
2762 case AArch64::SEH_SetFP:
2766 case AArch64::SEH_AddFP:
2770 case AArch64::SEH_Nop:
2774 case AArch64::SEH_PrologEnd:
2778 case AArch64::SEH_EpilogStart:
2782 case AArch64::SEH_EpilogEnd:
2786 case AArch64::SEH_PACSignLR:
2790 case AArch64::SEH_SaveAnyRegQP:
2791 assert(
MI->getOperand(1).getImm() -
MI->getOperand(0).getImm() == 1 &&
2792 "Non-consecutive registers not allowed for save_any_reg");
2793 assert(
MI->getOperand(2).getImm() >= 0 &&
2794 "SaveAnyRegQP SEH opcode offset must be non-negative");
2795 assert(
MI->getOperand(2).getImm() <= 1008 &&
2796 "SaveAnyRegQP SEH opcode offset must fit into 6 bits");
2798 MI->getOperand(2).getImm());
2801 case AArch64::SEH_SaveAnyRegQPX:
2802 assert(
MI->getOperand(1).getImm() -
MI->getOperand(0).getImm() == 1 &&
2803 "Non-consecutive registers not allowed for save_any_reg");
2804 assert(
MI->getOperand(2).getImm() < 0 &&
2805 "SaveAnyRegQPX SEH opcode offset must be negative");
2806 assert(
MI->getOperand(2).getImm() >= -1008 &&
2807 "SaveAnyRegQPX SEH opcode offset must fit into 6 bits");
2809 -
MI->getOperand(2).getImm());
2815 MCInstLowering.Lower(
MI, TmpInst);
2816 EmitToStreamer(*OutStreamer, TmpInst);
2832 MCInstLowering.lowerOperand(
2846 MCInstLowering.lowerOperand(
2856 .addReg(AArch64::X16)
2857 .addReg(AArch64::X16)
2868void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(
Module &M,
2903 .addReg(AArch64::SP)
2904 .addReg(AArch64::FP)
2905 .addReg(AArch64::LR)
2906 .addReg(AArch64::SP)
2911 .addReg(AArch64::FP)
2912 .addReg(AArch64::SP)
2917 for (
int I = 0;
I != 4; ++
I)
2919 .addReg(AArch64::SP)
2920 .addReg(AArch64::X1 + 2 *
I)
2921 .addReg(AArch64::X0 + 2 *
I)
2922 .addReg(AArch64::SP)
2926 for (
int I = 0;
I != 4; ++
I)
2928 .addReg(AArch64::SP)
2929 .addReg(AArch64::D1 + 2 *
I)
2930 .addReg(AArch64::D0 + 2 *
I)
2931 .addReg(AArch64::SP)
2945 MCInstLowering.lowerOperand(
2959 MCInstLowering.lowerOperand(
2969 .addReg(AArch64::X0)
2970 .addReg(AArch64::X16)
2975 .addReg(AArch64::X16)
2976 .addReg(AArch64::X0)
2981 for (
int I = 3;
I != -1; --
I)
2983 .addReg(AArch64::SP)
2984 .addReg(AArch64::D1 + 2 *
I)
2985 .addReg(AArch64::D0 + 2 *
I)
2986 .addReg(AArch64::SP)
2990 for (
int I = 3;
I != -1; --
I)
2992 .addReg(AArch64::SP)
2993 .addReg(AArch64::X1 + 2 *
I)
2994 .addReg(AArch64::X0 + 2 *
I)
2995 .addReg(AArch64::SP)
3000 .addReg(AArch64::SP)
3001 .addReg(AArch64::FP)
3002 .addReg(AArch64::LR)
3003 .addReg(AArch64::SP)
3014const MCExpr *AArch64AsmPrinter::lowerConstant(
const Constant *CV) {
3015 if (
const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
static cl::opt< PtrauthCheckMode > PtrauthAuthChecks("aarch64-ptrauth-auth-checks", cl::Hidden, cl::values(clEnumValN(Unchecked, "none", "don't test for failure"), clEnumValN(Poison, "poison", "poison on failure"), clEnumValN(Trap, "trap", "trap on failure")), cl::desc("Check pointer authentication auth/resign failures"), cl::init(Default))
static void emitAuthenticatedPointer(MCStreamer &OutStreamer, MCSymbol *StubLabel, const MCExpr *StubAuthPtrRef)
LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64AsmPrinter()
static MCDisassembler::DecodeStatus addOperand(MCInst &Inst, const MCOperand &Opnd)
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
#define LLVM_EXTERNAL_VISIBILITY
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
Module.h This file contains the declarations for the Module class.
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
const char LLVMTargetMachineRef TM
static SDValue lowerConstant(SDValue Op, SelectionDAG &DAG, const RISCVSubtarget &Subtarget)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool printOperand(raw_ostream &OS, const SelectionDAG *G, const SDValue Value)
This file defines the SmallString class.
This file defines the SmallVector class.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
static bool printAsmMRegister(const X86AsmPrinter &P, const MachineOperand &MO, char Mode, raw_ostream &O)
static const AArch64AuthMCExpr * create(const MCExpr *Expr, uint16_t Discriminator, AArch64PACKey::ID Key, bool HasAddressDiversity, MCContext &Ctx)
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
std::optional< std::string > getOutliningStyle() const
static const char * getRegisterName(MCRegister Reg, unsigned AltIdx=AArch64::NoRegAltName)
static const AArch64MCExpr * create(const MCExpr *Expr, VariantKind Kind, MCContext &Ctx)
AArch64MCInstLower - This class is used to lower an MachineInstr into an MCInst.
bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const
virtual void emitARM64WinCFISaveRegP(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveRegPX(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveAnyRegQP(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveFReg(unsigned Reg, int Offset)
virtual void emitARM64WinCFIPACSignLR()
virtual void emitARM64WinCFISaveFRegPX(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveRegX(unsigned Reg, int Offset)
virtual void emitARM64WinCFIAllocStack(unsigned Size)
virtual void emitARM64WinCFISaveFPLRX(int Offset)
virtual void emitDirectiveVariantPCS(MCSymbol *Symbol)
Callback used to implement the .variant_pcs directive.
virtual void emitARM64WinCFIAddFP(unsigned Size)
virtual void emitARM64WinCFISaveFPLR(int Offset)
virtual void emitARM64WinCFISaveFRegP(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveAnyRegQPX(unsigned Reg, int Offset)
virtual void emitARM64WinCFISaveFRegX(unsigned Reg, int Offset)
virtual void emitARM64WinCFISetFP()
virtual void emitARM64WinCFIEpilogEnd()
virtual void emitARM64WinCFIPrologEnd()
void emitNoteSection(unsigned Flags, uint64_t PAuthABIPlatform=-1, uint64_t PAuthABIVersion=-1)
Callback used to implement the .note.gnu.property section.
virtual void emitARM64WinCFISaveReg(unsigned Reg, int Offset)
virtual void emitARM64WinCFINop()
virtual void emitARM64WinCFISaveLRPair(unsigned Reg, int Offset)
virtual void emitARM64WinCFIEpilogStart()
This implementation is used for AArch64 ELF targets (Linux in particular).
AArch64_MachoTargetObjectFile - This TLOF implementation is used for Darwin.
Class for arbitrary precision integers.
Represent the analysis usage information of a pass.
void setPreservesAll()
Set by analyses that do not transform their input at all.
This class is intended to be used as a driving class for all asm writers.
virtual void emitInstruction(const MachineInstr *)
Targets should implement this to emit instructions.
virtual const MCExpr * lowerConstantPtrAuth(const ConstantPtrAuth &CPA)
void emitXRayTable()
Emit a table with all XRay instrumentation points.
virtual void emitGlobalAlias(const Module &M, const GlobalAlias &GA)
virtual MCSymbol * GetCPISymbol(unsigned CPID) const
Return the symbol for the specified constant pool entry.
virtual void emitMachOIFuncStubHelperBody(Module &M, const GlobalIFunc &GI, MCSymbol *LazyPointer)
virtual void emitJumpTableInfo()
Print assembly representations of the jump tables used by the current function to the current output ...
virtual void SetupMachineFunction(MachineFunction &MF)
This should be called when a new MachineFunction is being processed from runOnMachineFunction.
void emitFunctionBody()
This method emits the body and trailer for a function.
virtual void emitStartOfAsmFile(Module &)
This virtual method can be overridden by targets that want to emit something at the start of their fi...
virtual void emitEndOfAsmFile(Module &)
This virtual method can be overridden by targets that want to emit something at the end of their file...
virtual void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI, MCSymbol *LazyPointer)
void getAnalysisUsage(AnalysisUsage &AU) const override
Record analysis usage.
virtual bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const
virtual const MCSubtargetInfo * getIFuncMCSubtargetInfo() const
getSubtargetInfo() cannot be used where this is needed because we don't have a MachineFunction when w...
bool runOnMachineFunction(MachineFunction &MF) override
Emit the specified function out to the OutStreamer.
virtual const MCExpr * lowerConstant(const Constant *CV)
Lower the specified LLVM Constant to an MCExpr.
virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant as...
virtual void emitFunctionBodyEnd()
Targets can override this to emit stuff after the last basic block in the function.
virtual void emitFunctionEntryLabel()
EmitFunctionEntryLabel - Emit the label that is the entrypoint for the function.
virtual std::tuple< const MCSymbol *, uint64_t, const MCSymbol *, codeview::JumpTableEntrySize > getCodeViewJumpTableInfo(int JTI, const MachineInstr *BranchInstr, const MCSymbol *BranchLabel) const
Gets information required to create a CodeView debug symbol for a jump table.
virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant.
virtual const MCExpr * lowerBlockAddressConstant(const BlockAddress &BA)
Lower the specified BlockAddress to an MCExpr.
The address of a basic block.
Function * getFunction() const
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
A signed pointer, in the ptrauth sense.
Constant * getPointer() const
The pointer that is signed in this ptrauth signed pointer.
ConstantInt * getKey() const
The Key ID, an i32 constant.
bool hasAddressDiscriminator() const
Whether there is any non-null address discriminator.
ConstantInt * getDiscriminator() const
The integer discriminator, an i64 constant, or 0.
This is an important base class in LLVM.
This class represents an Operation in the Expression.
const Constant * getAliasee() const
const Constant * getResolver() const
bool hasLocalLinkage() const
void emitError(uint64_t LocCookie, const Twine &ErrorStr)
emitError - Emit an error message to the currently installed error handler with optional location inf...
static const MCBinaryExpr * createLShr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
static const MCBinaryExpr * createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
static const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Context object for machine code objects.
Base class for the full range of assembler expressions which are needed for parsing.
MCInstBuilder & addReg(unsigned Reg)
Add a new register operand.
MCInstBuilder & addImm(int64_t Val)
Add a new integer immediate operand.
MCInstBuilder & addExpr(const MCExpr *Val)
Add a new MCExpr operand.
Instances of this class represent a single low-level machine instruction.
void addOperand(const MCOperand Op)
void setOpcode(unsigned Op)
MCSection * getDataSection() const
Instances of this class represent operands of the MCInst class.
static MCOperand createReg(unsigned Reg)
static MCOperand createExpr(const MCExpr *Val)
static MCOperand createImm(int64_t Val)
uint16_t getEncodingValue(MCRegister RegNo) const
Returns the encoding for RegNo.
Instances of this class represent a uniqued identifier for a section in the current translation unit.
Streaming machine code generation interface.
virtual void emitCFIBKeyFrame()
virtual void beginCOFFSymbolDef(const MCSymbol *Symbol)
Start emitting COFF symbol definition.
virtual void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI)
Emit the given Instruction into the current section.
virtual void emitCOFFSymbolType(int Type)
Emit the type of the symbol.
virtual bool hasRawTextSupport() const
Return true if this asm streamer supports emitting unformatted text to the .s file with EmitRawText.
virtual void endCOFFSymbolDef()
Marks the end of the symbol definition.
MCContext & getContext() const
virtual void AddComment(const Twine &T, bool EOL=true)
Add a textual comment.
virtual void emitCFIMTETaggedFrame()
void emitValue(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc())
virtual void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc())
Emit a label for Symbol into the current section.
MCTargetStreamer * getTargetStreamer()
void emitRawText(const Twine &String)
If this file is backed by a assembly streamer, this dumps the specified string in the output ....
virtual void emitCOFFSymbolStorageClass(int StorageClass)
Emit the storage class of the symbol.
Generic base class for all target subtargets.
Represent a reference to a symbol from inside an expression.
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
StringRef getName() const
getName - Get the symbol name.
MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Representation of each machine instruction.
iterator_range< mop_iterator > operands()
const MachineOperand & getOperand(unsigned i) const
const std::vector< MachineJumpTableEntry > & getJumpTables() const
MachineModuleInfoELF - This is a MachineModuleInfoImpl implementation for ELF targets.
ExprStubListTy getAuthGVStubList()
MachineModuleInfoMachO - This is a MachineModuleInfoImpl implementation for MachO targets.
ExprStubListTy getAuthGVStubList()
MachineOperand class - Representation of each machine instruction operand.
unsigned getSubReg() const
static MachineOperand CreateMCSymbol(MCSymbol *Sym, unsigned TargetFlags=0)
const GlobalValue * getGlobal() const
static MachineOperand CreateES(const char *SymName, unsigned TargetFlags=0)
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
const BlockAddress * getBlockAddress() const
void setOffset(int64_t Offset)
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
Register getReg() const
getReg - Returns the register number.
@ MO_Immediate
Immediate operand.
@ MO_GlobalAddress
Address of a global value.
@ MO_BlockAddress
Address of a basic block.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
int64_t getOffset() const
Return the offset from the symbol in this operand.
A Module instance is used to store all the information related to an LLVM module.
Pass interface - Implemented by all 'passes'.
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
MI-level patchpoint operands.
Wrapper class representing virtual and physical registers.
static SectionKind getMetadata()
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
MI-level stackmap operands.
uint32_t getNumPatchBytes() const
Return the number of patchable bytes the given stackmap should emit.
void recordStatepoint(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a statepoint instruction.
void recordPatchPoint(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a patchpoint instruction.
void recordStackMap(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a stackmap instruction.
MI-level Statepoint operands.
StringRef - Represent a constant reference to a string, i.e.
constexpr const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
virtual MCSection * getSectionForJumpTable(const Function &F, const TargetMachine &TM) const
Primary interface to the complete machine description for the target machine.
MCRegister getRegister(unsigned i) const
Return the specified register in the class.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
bool regsOverlap(Register RegA, Register RegB) const
Returns true if the two registers are equal or alias each other.
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
const Value * stripAndAccumulateConstantOffsets(const DataLayout &DL, APInt &Offset, bool AllowNonInbounds, bool AllowInvariantGroup=false, function_ref< bool(Value &Value, APInt &Offset)> ExternalAnalysis=nullptr) const
Accumulate the constant offset this value has compared to a base pointer.
LLVMContext & getContext() const
All values hold a context through their type.
StringRef getName() const
Return a constant reference to the value's name.
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an SmallVector or SmallString.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_G1
MO_G1 - A symbol operand with this flag (granule 1) represents the bits 16-31 of a 64-bit address,...
@ MO_S
MO_S - Indicates that the bits of the symbol operand represented by MO_G0 etc are signed.
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_G0
MO_G0 - A symbol operand with this flag (granule 0) represents the bits 0-15 of a 64-bit address,...
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_TLS
MO_TLS - Indicates that the operand being accessed is some kind of thread-local symbol.
static unsigned getShiftValue(unsigned Imm)
getShiftValue - Extract the shift value.
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
SymbolStorageClass
Storage class tells where and what the symbol represents.
@ IMAGE_SYM_CLASS_EXTERNAL
External symbol.
@ IMAGE_SYM_CLASS_STATIC
Static.
@ IMAGE_SYM_DTYPE_NULL
No complex type; simple scalar variable.
@ IMAGE_SYM_DTYPE_FUNCTION
A function that returns a base type.
@ SCT_COMPLEX_TYPE_SHIFT
Type is formed as (base + (derived << SCT_COMPLEX_TYPE_SHIFT))
@ AArch64_VectorCall
Used between AArch64 Advanced SIMD functions.
@ AArch64_SVE_VectorCall
Used between AArch64 SVE functions.
@ GNU_PROPERTY_AARCH64_FEATURE_1_BTI
@ GNU_PROPERTY_AARCH64_FEATURE_1_PAC
@ GNU_PROPERTY_AARCH64_FEATURE_1_GCS
@ S_REGULAR
S_REGULAR - Regular section.
Reg
All possible values of the reg field in the ModR/M byte.
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
static unsigned getXPACOpcodeForKey(AArch64PACKey::ID K)
Return XPAC opcode to be used for a ptrauth strip using the given key.
Target & getTheAArch64beTarget()
Target & getTheAArch64leTarget()
static unsigned getXRegFromWReg(unsigned Reg)
static unsigned getXRegFromXRegTuple(unsigned RegTuple)
Target & getTheAArch64_32Target()
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Target & getTheARM64_32Target()
@ MCAF_SubsectionsViaSymbols
.subsections_via_symbols (MachO)
static unsigned getWRegFromXReg(unsigned Reg)
Target & getTheARM64Target()
static unsigned getPACOpcodeForKey(AArch64PACKey::ID K, bool Zero)
Return PAC opcode to be used for a ptrauth sign using the given key, or its PAC*Z variant that doesn'...
static unsigned getAUTOpcodeForKey(AArch64PACKey::ID K, bool Zero)
Return AUT opcode to be used for a ptrauth auth using the given key, or its AUT*Z variant that doesn'...
@ MCSA_Global
.type _foo, @gnu_unique_object
@ MCSA_WeakAntiDep
.weak_anti_dep (COFF)
@ MCSA_ELF_TypeFunction
.type _foo, STT_FUNC # aka @function
@ MCSA_Hidden
.hidden (ELF)
This struct is a compact representation of a valid (non-zero power of two) alignment.
RegisterAsmPrinter - Helper template for registering a target specific assembly printer,...