1//===-- RISCVAsmPrinter.cpp - RISC-V LLVM assembly writer -----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains a printer that converts from our internal representation
10// of machine-dependent LLVM code to the RISC-V assembly language.
11//
12//===----------------------------------------------------------------------===//
13
14#include "MCTargetDesc/RISCVBaseInfo.h"
15#include "MCTargetDesc/RISCVInstPrinter.h"
16#include "MCTargetDesc/RISCVMCExpr.h"
17#include "MCTargetDesc/RISCVMatInt.h"
18#include "MCTargetDesc/RISCVTargetStreamer.h"
19#include "RISCV.h"
20#include "RISCVMachineFunctionInfo.h"
21#include "RISCVTargetMachine.h"
22#include "TargetInfo/RISCVTargetInfo.h"
23#include "llvm/ADT/APInt.h"
24#include "llvm/ADT/Statistic.h"
25#include "llvm/BinaryFormat/ELF.h"
26#include "llvm/CodeGen/AsmPrinter.h"
27#include "llvm/CodeGen/MachineConstantPool.h"
28#include "llvm/CodeGen/MachineFunctionPass.h"
29#include "llvm/CodeGen/MachineInstr.h"
30#include "llvm/CodeGen/MachineModuleInfo.h"
31#include "llvm/IR/Module.h"
32#include "llvm/MC/MCAsmInfo.h"
33#include "llvm/MC/MCContext.h"
34#include "llvm/MC/MCInst.h"
35#include "llvm/MC/MCInstBuilder.h"
36#include "llvm/MC/MCObjectFileInfo.h"
37#include "llvm/MC/MCSectionELF.h"
38#include "llvm/MC/MCStreamer.h"
39#include "llvm/MC/MCSymbol.h"
40#include "llvm/MC/TargetRegistry.h"
41#include "llvm/Support/raw_ostream.h"
42#include "llvm/TargetParser/RISCVISAInfo.h"
43#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
44
45using namespace llvm;
46
47#define DEBUG_TYPE "asm-printer"
48
49STATISTIC(RISCVNumInstrsCompressed,
50 "Number of RISC-V Compressed instructions emitted");
51
52namespace llvm {
53extern const SubtargetFeatureKV RISCVFeatureKV[RISCV::NumSubtargetFeatures];
54} // namespace llvm
55
56namespace {
57class RISCVAsmPrinter : public AsmPrinter {
58 const RISCVSubtarget *STI;
59
60public:
61 explicit RISCVAsmPrinter(TargetMachine &TM,
62 std::unique_ptr<MCStreamer> Streamer)
63 : AsmPrinter(TM, std::move(Streamer)) {}
64
65 StringRef getPassName() const override { return "RISC-V Assembly Printer"; }
66
67 void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
68 const MachineInstr &MI);
69
70 void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
71 const MachineInstr &MI);
72
73 void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
74 const MachineInstr &MI);
75
76 bool runOnMachineFunction(MachineFunction &MF) override;
77
78 void emitInstruction(const MachineInstr *MI) override;
79
80 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
81 const char *ExtraCode, raw_ostream &OS) override;
82 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
83 const char *ExtraCode, raw_ostream &OS) override;
84
85 // Returns whether Inst is compressed.
86 bool EmitToStreamer(MCStreamer &S, const MCInst &Inst);
87 bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
88 const MachineInstr *MI);
89
90 typedef std::tuple<unsigned, uint32_t> HwasanMemaccessTuple;
91 std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
92 void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
93 void LowerKCFI_CHECK(const MachineInstr &MI);
94 void EmitHwasanMemaccessSymbols(Module &M);
95
96 // Wrapper needed for tblgenned pseudo lowering.
97 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const;
98
99 void emitStartOfAsmFile(Module &M) override;
100 void emitEndOfAsmFile(Module &M) override;
101
102 void emitFunctionEntryLabel() override;
103 bool emitDirectiveOptionArch();
104
105private:
106 void emitAttributes(const MCSubtargetInfo &SubtargetInfo);
107
108 void emitNTLHint(const MachineInstr *MI);
109
110 bool lowerToMCInst(const MachineInstr *MI, MCInst &OutMI);
111};
112}
113
114void RISCVAsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
115 const MachineInstr &MI) {
116 unsigned NOPBytes = STI->hasStdExtCOrZca() ? 2 : 4;
117 unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();
118
119 auto &Ctx = OutStreamer.getContext();
120 MCSymbol *MILabel = Ctx.createTempSymbol();
121 OutStreamer.emitLabel(Symbol: MILabel);
122
123 SM.recordStackMap(L: *MILabel, MI);
124 assert(NumNOPBytes % NOPBytes == 0 &&
125 "Invalid number of NOP bytes requested!");
126
127 // Scan ahead to trim the shadow.
128 const MachineBasicBlock &MBB = *MI.getParent();
129 MachineBasicBlock::const_iterator MII(MI);
130 ++MII;
131 while (NumNOPBytes > 0) {
132 if (MII == MBB.end() || MII->isCall() ||
133 MII->getOpcode() == RISCV::DBG_VALUE ||
134 MII->getOpcode() == TargetOpcode::PATCHPOINT ||
135 MII->getOpcode() == TargetOpcode::STACKMAP)
136 break;
137 ++MII;
138 NumNOPBytes -= 4;
139 }
140
141 // Emit nops.
142 emitNops(N: NumNOPBytes / NOPBytes);
143}
144
145// Lower a patchpoint of the form:
146// [<def>], <id>, <numBytes>, <target>, <numArgs>
147void RISCVAsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
148 const MachineInstr &MI) {
149 unsigned NOPBytes = STI->hasStdExtCOrZca() ? 2 : 4;
150
151 auto &Ctx = OutStreamer.getContext();
152 MCSymbol *MILabel = Ctx.createTempSymbol();
153 OutStreamer.emitLabel(Symbol: MILabel);
154 SM.recordPatchPoint(L: *MILabel, MI);
155
156 PatchPointOpers Opers(&MI);
157
158 const MachineOperand &CalleeMO = Opers.getCallTarget();
159 unsigned EncodedBytes = 0;
160
161 if (CalleeMO.isImm()) {
162 uint64_t CallTarget = CalleeMO.getImm();
163 if (CallTarget) {
164 assert((CallTarget & 0xFFFF'FFFF'FFFF) == CallTarget &&
165 "High 16 bits of call target should be zero.");
166 // Materialize the jump address:
167 SmallVector<MCInst, 8> Seq;
168 RISCVMatInt::generateMCInstSeq(Val: CallTarget, STI: *STI, DestReg: RISCV::X1, Insts&: Seq);
169 for (MCInst &Inst : Seq) {
170 bool Compressed = EmitToStreamer(S&: OutStreamer, Inst);
171 EncodedBytes += Compressed ? 2 : 4;
172 }
173 bool Compressed = EmitToStreamer(S&: OutStreamer, Inst: MCInstBuilder(RISCV::JALR)
174 .addReg(Reg: RISCV::X1)
175 .addReg(Reg: RISCV::X1)
176 .addImm(Val: 0));
177 EncodedBytes += Compressed ? 2 : 4;
178 }
179 } else if (CalleeMO.isGlobal()) {
180 MCOperand CallTargetMCOp;
181 lowerOperand(MO: CalleeMO, MCOp&: CallTargetMCOp);
182 EmitToStreamer(S&: OutStreamer,
183 Inst: MCInstBuilder(RISCV::PseudoCALL).addOperand(Op: CallTargetMCOp));
184 EncodedBytes += 8;
185 }
186
187 // Emit padding.
188 unsigned NumBytes = Opers.getNumPatchBytes();
189 assert(NumBytes >= EncodedBytes &&
190 "Patchpoint can't request size less than the length of a call.");
191 assert((NumBytes - EncodedBytes) % NOPBytes == 0 &&
192 "Invalid number of NOP bytes requested!");
193 emitNops(N: (NumBytes - EncodedBytes) / NOPBytes);
194}
195
196void RISCVAsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
197 const MachineInstr &MI) {
198 unsigned NOPBytes = STI->hasStdExtCOrZca() ? 2 : 4;
199
200 StatepointOpers SOpers(&MI);
201 if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
202 assert(PatchBytes % NOPBytes == 0 &&
203 "Invalid number of NOP bytes requested!");
204 emitNops(N: PatchBytes / NOPBytes);
205 } else {
206 // Lower call target and choose correct opcode
207 const MachineOperand &CallTarget = SOpers.getCallTarget();
208 MCOperand CallTargetMCOp;
209 switch (CallTarget.getType()) {
210 case MachineOperand::MO_GlobalAddress:
211 case MachineOperand::MO_ExternalSymbol:
212 lowerOperand(MO: CallTarget, MCOp&: CallTargetMCOp);
213 EmitToStreamer(
214 S&: OutStreamer,
215 Inst: MCInstBuilder(RISCV::PseudoCALL).addOperand(Op: CallTargetMCOp));
216 break;
217 case MachineOperand::MO_Immediate:
218 CallTargetMCOp = MCOperand::createImm(Val: CallTarget.getImm());
219 EmitToStreamer(S&: OutStreamer, Inst: MCInstBuilder(RISCV::JAL)
220 .addReg(Reg: RISCV::X1)
221 .addOperand(Op: CallTargetMCOp));
222 break;
223 case MachineOperand::MO_Register:
224 CallTargetMCOp = MCOperand::createReg(Reg: CallTarget.getReg());
225 EmitToStreamer(S&: OutStreamer, Inst: MCInstBuilder(RISCV::JALR)
226 .addReg(Reg: RISCV::X1)
227 .addOperand(Op: CallTargetMCOp)
228 .addImm(Val: 0));
229 break;
230 default:
231 llvm_unreachable("Unsupported operand type in statepoint call target");
232 break;
233 }
234 }
235
236 auto &Ctx = OutStreamer.getContext();
237 MCSymbol *MILabel = Ctx.createTempSymbol();
238 OutStreamer.emitLabel(Symbol: MILabel);
239 SM.recordStatepoint(L: *MILabel, MI);
240}
241
242bool RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
243 MCInst CInst;
244 bool Res = RISCVRVC::compress(OutInst&: CInst, MI: Inst, STI: *STI);
245 if (Res)
246 ++RISCVNumInstrsCompressed;
247 AsmPrinter::EmitToStreamer(S&: *OutStreamer, Inst: Res ? CInst : Inst);
248 return Res;
249}
250
251// Simple pseudo-instructions have their lowering (with expansion to real
252// instructions) auto-generated.
253#include "RISCVGenMCPseudoLowering.inc"
254
255// If the target supports Zihintntl and the instruction has a nontemporal
256// MachineMemOperand, emit an NTLH hint instruction before it.
257void RISCVAsmPrinter::emitNTLHint(const MachineInstr *MI) {
258 if (!STI->hasStdExtZihintntl())
259 return;
260
261 if (MI->memoperands_empty())
262 return;
263
264 MachineMemOperand *MMO = *(MI->memoperands_begin());
265 if (!MMO->isNonTemporal())
266 return;
267
268 unsigned NontemporalMode = 0;
269 if (MMO->getFlags() & MONontemporalBit0)
270 NontemporalMode += 0b1;
271 if (MMO->getFlags() & MONontemporalBit1)
272 NontemporalMode += 0b10;
273
274 MCInst Hint;
275 if (STI->hasStdExtCOrZca() && STI->enableRVCHintInstrs())
276 Hint.setOpcode(RISCV::C_ADD_HINT);
277 else
278 Hint.setOpcode(RISCV::ADD);
279
280 Hint.addOperand(Op: MCOperand::createReg(Reg: RISCV::X0));
281 Hint.addOperand(Op: MCOperand::createReg(Reg: RISCV::X0));
282 Hint.addOperand(Op: MCOperand::createReg(Reg: RISCV::X2 + NontemporalMode));
283
284 EmitToStreamer(S&: *OutStreamer, Inst: Hint);
285}
286
287void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) {
288 RISCV_MC::verifyInstructionPredicates(Opcode: MI->getOpcode(),
289 Features: getSubtargetInfo().getFeatureBits());
290
291 emitNTLHint(MI);
292
293 // Do any auto-generated pseudo lowerings.
294 if (emitPseudoExpansionLowering(OutStreamer&: *OutStreamer, MI))
295 return;
296
297
298 switch (MI->getOpcode()) {
299 case RISCV::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
300 LowerHWASAN_CHECK_MEMACCESS(MI: *MI);
301 return;
302 case RISCV::KCFI_CHECK:
303 LowerKCFI_CHECK(MI: *MI);
304 return;
305 case RISCV::PseudoRVVInitUndefM1:
306 case RISCV::PseudoRVVInitUndefM2:
307 case RISCV::PseudoRVVInitUndefM4:
308 case RISCV::PseudoRVVInitUndefM8:
309 return;
310 case TargetOpcode::STACKMAP:
311 return LowerSTACKMAP(OutStreamer&: *OutStreamer, SM, MI: *MI);
312 case TargetOpcode::PATCHPOINT:
313 return LowerPATCHPOINT(OutStreamer&: *OutStreamer, SM, MI: *MI);
314 case TargetOpcode::STATEPOINT:
315 return LowerSTATEPOINT(OutStreamer&: *OutStreamer, SM, MI: *MI);
316 }
317
318 MCInst OutInst;
319 if (!lowerToMCInst(MI, OutMI&: OutInst))
320 EmitToStreamer(S&: *OutStreamer, Inst: OutInst);
321}
322
323bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
324 const char *ExtraCode, raw_ostream &OS) {
325 // First try the generic code, which knows about modifiers like 'c' and 'n'.
326 if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
327 return false;
328
329 const MachineOperand &MO = MI->getOperand(i: OpNo);
330 if (ExtraCode && ExtraCode[0]) {
331 if (ExtraCode[1] != 0)
332 return true; // Unknown modifier.
333
334 switch (ExtraCode[0]) {
335 default:
336 return true; // Unknown modifier.
337 case 'z': // Print zero register if zero, regular printing otherwise.
338 if (MO.isImm() && MO.getImm() == 0) {
339 OS << RISCVInstPrinter::getRegisterName(Reg: RISCV::X0);
340 return false;
341 }
342 break;
343 case 'i': // Literal 'i' if operand is not a register.
344 if (!MO.isReg())
345 OS << 'i';
346 return false;
347 }
348 }
349
350 switch (MO.getType()) {
351 case MachineOperand::MO_Immediate:
352 OS << MO.getImm();
353 return false;
354 case MachineOperand::MO_Register:
355 OS << RISCVInstPrinter::getRegisterName(Reg: MO.getReg());
356 return false;
357 case MachineOperand::MO_GlobalAddress:
358 PrintSymbolOperand(MO, OS);
359 return false;
360 case MachineOperand::MO_BlockAddress: {
361 MCSymbol *Sym = GetBlockAddressSymbol(BA: MO.getBlockAddress());
362 Sym->print(OS, MAI);
363 return false;
364 }
365 default:
366 break;
367 }
368
369 return true;
370}
371
372bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
373 unsigned OpNo,
374 const char *ExtraCode,
375 raw_ostream &OS) {
376 if (ExtraCode)
377 return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
378
379 const MachineOperand &AddrReg = MI->getOperand(i: OpNo);
380 assert(MI->getNumOperands() > OpNo + 1 && "Expected additional operand");
381 const MachineOperand &Offset = MI->getOperand(i: OpNo + 1);
382 // All memory operands should have a register and an immediate operand (see
383 // RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand).
384 if (!AddrReg.isReg())
385 return true;
386 if (!Offset.isImm() && !Offset.isGlobal() && !Offset.isBlockAddress() &&
387 !Offset.isMCSymbol())
388 return true;
389
390 MCOperand MCO;
391 if (!lowerOperand(MO: Offset, MCOp&: MCO))
392 return true;
393
394 if (Offset.isImm())
395 OS << MCO.getImm();
396 else if (Offset.isGlobal() || Offset.isBlockAddress() || Offset.isMCSymbol())
397 OS << *MCO.getExpr();
398 OS << "(" << RISCVInstPrinter::getRegisterName(Reg: AddrReg.getReg()) << ")";
399 return false;
400}
401
402bool RISCVAsmPrinter::emitDirectiveOptionArch() {
403 RISCVTargetStreamer &RTS =
404 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
405 SmallVector<RISCVOptionArchArg> NeedEmitStdOptionArgs;
406 const MCSubtargetInfo &MCSTI = *TM.getMCSubtargetInfo();
407 for (const auto &Feature : RISCVFeatureKV) {
408 if (STI->hasFeature(Feature: Feature.Value) == MCSTI.hasFeature(Feature: Feature.Value))
409 continue;
410
411 if (!llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext: Feature.Key))
412 continue;
413
414 auto Delta = STI->hasFeature(Feature: Feature.Value) ? RISCVOptionArchArgType::Plus
415 : RISCVOptionArchArgType::Minus;
416 NeedEmitStdOptionArgs.emplace_back(Args&: Delta, Args: Feature.Key);
417 }
418 if (!NeedEmitStdOptionArgs.empty()) {
419 RTS.emitDirectiveOptionPush();
420 RTS.emitDirectiveOptionArch(Args: NeedEmitStdOptionArgs);
421 return true;
422 }
423
424 return false;
425}
426
427bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
428 STI = &MF.getSubtarget<RISCVSubtarget>();
429 RISCVTargetStreamer &RTS =
430 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
431
432 bool EmittedOptionArch = emitDirectiveOptionArch();
433
434 SetupMachineFunction(MF);
435 emitFunctionBody();
436
437 if (EmittedOptionArch)
438 RTS.emitDirectiveOptionPop();
439 return false;
440}
441
442void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) {
443 RISCVTargetStreamer &RTS =
444 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
445 if (const MDString *ModuleTargetABI =
446 dyn_cast_or_null<MDString>(Val: M.getModuleFlag(Key: "target-abi")))
447 RTS.setTargetABI(RISCVABI::getTargetABI(ABIName: ModuleTargetABI->getString()));
448
449 MCSubtargetInfo SubtargetInfo = *TM.getMCSubtargetInfo();
450
451 // Use module flag to update feature bits.
452 if (auto *MD = dyn_cast_or_null<MDNode>(Val: M.getModuleFlag(Key: "riscv-isa"))) {
453 for (auto &ISA : MD->operands()) {
454 if (auto *ISAString = dyn_cast_or_null<MDString>(Val: ISA)) {
455 auto ParseResult = llvm::RISCVISAInfo::parseArchString(
456 Arch: ISAString->getString(), /*EnableExperimentalExtension=*/true,
457 /*ExperimentalExtensionVersionCheck=*/true);
458 if (!errorToBool(Err: ParseResult.takeError())) {
459 auto &ISAInfo = *ParseResult;
460 for (const auto &Feature : RISCVFeatureKV) {
461 if (ISAInfo->hasExtension(Ext: Feature.Key) &&
462 !SubtargetInfo.hasFeature(Feature: Feature.Value))
463 SubtargetInfo.ToggleFeature(FS: Feature.Key);
464 }
465 }
466 }
467 }
468
469 RTS.setFlagsFromFeatures(SubtargetInfo);
470 }
471
472 if (TM.getTargetTriple().isOSBinFormatELF())
473 emitAttributes(SubtargetInfo);
474}
475
476void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) {
477 RISCVTargetStreamer &RTS =
478 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
479
480 if (TM.getTargetTriple().isOSBinFormatELF())
481 RTS.finishAttributeSection();
482 EmitHwasanMemaccessSymbols(M);
483}
484
485void RISCVAsmPrinter::emitAttributes(const MCSubtargetInfo &SubtargetInfo) {
486 RISCVTargetStreamer &RTS =
487 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
488 // Use MCSubtargetInfo from TargetMachine. Individual functions may have
489 // attributes that differ from other functions in the module and we have no
490 // way to know which function is correct.
491 RTS.emitTargetAttributes(STI: SubtargetInfo, /*EmitStackAlign*/ true);
492}
493
494void RISCVAsmPrinter::emitFunctionEntryLabel() {
495 const auto *RMFI = MF->getInfo<RISCVMachineFunctionInfo>();
496 if (RMFI->isVectorCall()) {
497 auto &RTS =
498 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
499 RTS.emitDirectiveVariantCC(Symbol&: *CurrentFnSym);
500 }
501 return AsmPrinter::emitFunctionEntryLabel();
502}
503
504// Force static initialization.
505extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() {
506 RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());
507 RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target());
508}
509
510void RISCVAsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
511 Register Reg = MI.getOperand(i: 0).getReg();
512 uint32_t AccessInfo = MI.getOperand(i: 1).getImm();
513 MCSymbol *&Sym =
514 HwasanMemaccessSymbols[HwasanMemaccessTuple(Reg, AccessInfo)];
515 if (!Sym) {
516 // FIXME: Make this work on non-ELF.
517 if (!TM.getTargetTriple().isOSBinFormatELF())
518 report_fatal_error(reason: "llvm.hwasan.check.memaccess only supported on ELF");
519
520 std::string SymName = "__hwasan_check_x" + utostr(X: Reg - RISCV::X0) + "_" +
521 utostr(X: AccessInfo) + "_short";
522 Sym = OutContext.getOrCreateSymbol(Name: SymName);
523 }
524 auto Res = MCSymbolRefExpr::create(Symbol: Sym, Kind: MCSymbolRefExpr::VK_None, Ctx&: OutContext);
525 auto Expr = RISCVMCExpr::create(Expr: Res, Kind: RISCVMCExpr::VK_RISCV_CALL, Ctx&: OutContext);
526
527 EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::PseudoCALL).addExpr(Val: Expr));
528}
529
530void RISCVAsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
531 Register AddrReg = MI.getOperand(i: 0).getReg();
532 assert(std::next(MI.getIterator())->isCall() &&
533 "KCFI_CHECK not followed by a call instruction");
534 assert(std::next(MI.getIterator())->getOperand(0).getReg() == AddrReg &&
535 "KCFI_CHECK call target doesn't match call operand");
536
537 // Temporary registers for comparing the hashes. If a register is used
538 // for the call target, or reserved by the user, we can clobber another
539 // temporary register as the check is immediately followed by the
540 // call. The check defaults to X6/X7, but can fall back to X28-X31 if
541 // needed.
542 unsigned ScratchRegs[] = {RISCV::X6, RISCV::X7};
543 unsigned NextReg = RISCV::X28;
544 auto isRegAvailable = [&](unsigned Reg) {
545 return Reg != AddrReg && !STI->isRegisterReservedByUser(i: Reg);
546 };
547 for (auto &Reg : ScratchRegs) {
548 if (isRegAvailable(Reg))
549 continue;
550 while (!isRegAvailable(NextReg))
551 ++NextReg;
552 Reg = NextReg++;
553 if (Reg > RISCV::X31)
554 report_fatal_error(reason: "Unable to find scratch registers for KCFI_CHECK");
555 }
556
557 if (AddrReg == RISCV::X0) {
558 // Checking X0 makes no sense. Instead of emitting a load, zero
559 // ScratchRegs[0].
560 EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::ADDI)
561 .addReg(Reg: ScratchRegs[0])
562 .addReg(Reg: RISCV::X0)
563 .addImm(Val: 0));
564 } else {
565 // Adjust the offset for patchable-function-prefix. This assumes that
566 // patchable-function-prefix is the same for all functions.
567 int NopSize = STI->hasStdExtCOrZca() ? 2 : 4;
568 int64_t PrefixNops = 0;
569 (void)MI.getMF()
570 ->getFunction()
571 .getFnAttribute(Kind: "patchable-function-prefix")
572 .getValueAsString()
573 .getAsInteger(Radix: 10, Result&: PrefixNops);
574
575 // Load the target function type hash.
576 EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::LW)
577 .addReg(Reg: ScratchRegs[0])
578 .addReg(Reg: AddrReg)
579 .addImm(Val: -(PrefixNops * NopSize + 4)));
580 }
581
582 // Load the expected 32-bit type hash.
583 const int64_t Type = MI.getOperand(i: 1).getImm();
584 const int64_t Hi20 = ((Type + 0x800) >> 12) & 0xFFFFF;
585 const int64_t Lo12 = SignExtend64<12>(x: Type);
586 if (Hi20) {
587 EmitToStreamer(
588 S&: *OutStreamer,
589 Inst: MCInstBuilder(RISCV::LUI).addReg(Reg: ScratchRegs[1]).addImm(Val: Hi20));
590 }
591 if (Lo12 || Hi20 == 0) {
592 EmitToStreamer(S&: *OutStreamer,
593 Inst: MCInstBuilder((STI->hasFeature(Feature: RISCV::Feature64Bit) && Hi20)
594 ? RISCV::ADDIW
595 : RISCV::ADDI)
596 .addReg(Reg: ScratchRegs[1])
597 .addReg(Reg: ScratchRegs[1])
598 .addImm(Val: Lo12));
599 }
600
601 // Compare the hashes and trap if there's a mismatch.
602 MCSymbol *Pass = OutContext.createTempSymbol();
603 EmitToStreamer(S&: *OutStreamer,
604 Inst: MCInstBuilder(RISCV::BEQ)
605 .addReg(Reg: ScratchRegs[0])
606 .addReg(Reg: ScratchRegs[1])
607 .addExpr(Val: MCSymbolRefExpr::create(Symbol: Pass, Ctx&: OutContext)));
608
609 MCSymbol *Trap = OutContext.createTempSymbol();
610 OutStreamer->emitLabel(Symbol: Trap);
611 EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::EBREAK));
612 emitKCFITrapEntry(MF: *MI.getMF(), Symbol: Trap);
613 OutStreamer->emitLabel(Symbol: Pass);
614}
615
616void RISCVAsmPrinter::EmitHwasanMemaccessSymbols(Module &M) {
617 if (HwasanMemaccessSymbols.empty())
618 return;
619
620 assert(TM.getTargetTriple().isOSBinFormatELF());
621 // Use MCSubtargetInfo from TargetMachine. Individual functions may have
622 // attributes that differ from other functions in the module and we have no
623 // way to know which function is correct.
624 const MCSubtargetInfo &MCSTI = *TM.getMCSubtargetInfo();
625
626 MCSymbol *HwasanTagMismatchV2Sym =
627 OutContext.getOrCreateSymbol(Name: "__hwasan_tag_mismatch_v2");
628 // Annotate symbol as one having incompatible calling convention, so
629 // run-time linkers can instead eagerly bind this function.
630 auto &RTS =
631 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
632 RTS.emitDirectiveVariantCC(Symbol&: *HwasanTagMismatchV2Sym);
633
634 const MCSymbolRefExpr *HwasanTagMismatchV2Ref =
635 MCSymbolRefExpr::create(Symbol: HwasanTagMismatchV2Sym, Ctx&: OutContext);
636 auto Expr = RISCVMCExpr::create(Expr: HwasanTagMismatchV2Ref,
637 Kind: RISCVMCExpr::VK_RISCV_CALL, Ctx&: OutContext);
638
639 for (auto &P : HwasanMemaccessSymbols) {
640 unsigned Reg = std::get<0>(t: P.first);
641 uint32_t AccessInfo = std::get<1>(t: P.first);
642 MCSymbol *Sym = P.second;
643
644 unsigned Size =
645 1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);
646 OutStreamer->switchSection(Section: OutContext.getELFSection(
647 Section: ".text.hot", Type: ELF::SHT_PROGBITS,
648 Flags: ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, EntrySize: 0, Group: Sym->getName(),
649 /*IsComdat=*/true));
650
651 OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_ELF_TypeFunction);
652 OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_Weak);
653 OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_Hidden);
654 OutStreamer->emitLabel(Symbol: Sym);
655
656 // Extract shadow offset from ptr
657 OutStreamer->emitInstruction(
658 Inst: MCInstBuilder(RISCV::SLLI).addReg(Reg: RISCV::X6).addReg(Reg).addImm(Val: 8),
659 STI: MCSTI);
660 OutStreamer->emitInstruction(Inst: MCInstBuilder(RISCV::SRLI)
661 .addReg(Reg: RISCV::X6)
662 .addReg(Reg: RISCV::X6)
663 .addImm(Val: 12),
664 STI: MCSTI);
665 // load shadow tag in X6, X5 contains shadow base
666 OutStreamer->emitInstruction(Inst: MCInstBuilder(RISCV::ADD)
667 .addReg(Reg: RISCV::X6)
668 .addReg(Reg: RISCV::X5)
669 .addReg(Reg: RISCV::X6),
670 STI: MCSTI);
671 OutStreamer->emitInstruction(
672 Inst: MCInstBuilder(RISCV::LBU).addReg(Reg: RISCV::X6).addReg(Reg: RISCV::X6).addImm(Val: 0),
673 STI: MCSTI);
674 // Extract tag from X5 and compare it with loaded tag from shadow
675 OutStreamer->emitInstruction(
676 Inst: MCInstBuilder(RISCV::SRLI).addReg(Reg: RISCV::X7).addReg(Reg).addImm(Val: 56),
677 STI: MCSTI);
678 MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
679 // X7 contains tag from memory, while X6 contains tag from the pointer
680 OutStreamer->emitInstruction(
681 Inst: MCInstBuilder(RISCV::BNE)
682 .addReg(Reg: RISCV::X7)
683 .addReg(Reg: RISCV::X6)
684 .addExpr(Val: MCSymbolRefExpr::create(Symbol: HandleMismatchOrPartialSym,
685 Ctx&: OutContext)),
686 STI: MCSTI);
687 MCSymbol *ReturnSym = OutContext.createTempSymbol();
688 OutStreamer->emitLabel(Symbol: ReturnSym);
689 OutStreamer->emitInstruction(Inst: MCInstBuilder(RISCV::JALR)
690 .addReg(Reg: RISCV::X0)
691 .addReg(Reg: RISCV::X1)
692 .addImm(Val: 0),
693 STI: MCSTI);
694 OutStreamer->emitLabel(Symbol: HandleMismatchOrPartialSym);
695
696 OutStreamer->emitInstruction(Inst: MCInstBuilder(RISCV::ADDI)
697 .addReg(Reg: RISCV::X28)
698 .addReg(Reg: RISCV::X0)
699 .addImm(Val: 16),
700 STI: MCSTI);
701 MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
702 OutStreamer->emitInstruction(
703 Inst: MCInstBuilder(RISCV::BGEU)
704 .addReg(Reg: RISCV::X6)
705 .addReg(Reg: RISCV::X28)
706 .addExpr(Val: MCSymbolRefExpr::create(Symbol: HandleMismatchSym, Ctx&: OutContext)),
707 STI: MCSTI);
708
709 OutStreamer->emitInstruction(
710 Inst: MCInstBuilder(RISCV::ANDI).addReg(Reg: RISCV::X28).addReg(Reg).addImm(Val: 0xF),
711 STI: MCSTI);
712
713 if (Size != 1)
714 OutStreamer->emitInstruction(Inst: MCInstBuilder(RISCV::ADDI)
715 .addReg(Reg: RISCV::X28)
716 .addReg(Reg: RISCV::X28)
717 .addImm(Val: Size - 1),
718 STI: MCSTI);
719 OutStreamer->emitInstruction(
720 Inst: MCInstBuilder(RISCV::BGE)
721 .addReg(Reg: RISCV::X28)
722 .addReg(Reg: RISCV::X6)
723 .addExpr(Val: MCSymbolRefExpr::create(Symbol: HandleMismatchSym, Ctx&: OutContext)),
724 STI: MCSTI);
725
726 OutStreamer->emitInstruction(
727 Inst: MCInstBuilder(RISCV::ORI).addReg(Reg: RISCV::X6).addReg(Reg).addImm(Val: 0xF),
728 STI: MCSTI);
729 OutStreamer->emitInstruction(
730 Inst: MCInstBuilder(RISCV::LBU).addReg(Reg: RISCV::X6).addReg(Reg: RISCV::X6).addImm(Val: 0),
731 STI: MCSTI);
732 OutStreamer->emitInstruction(
733 Inst: MCInstBuilder(RISCV::BEQ)
734 .addReg(Reg: RISCV::X6)
735 .addReg(Reg: RISCV::X7)
736 .addExpr(Val: MCSymbolRefExpr::create(Symbol: ReturnSym, Ctx&: OutContext)),
737 STI: MCSTI);
738
739 OutStreamer->emitLabel(Symbol: HandleMismatchSym);
740
741 // | Previous stack frames... |
742 // +=================================+ <-- [SP + 256]
743 // | ... |
744 // | |
745 // | Stack frame space for x12 - x31.|
746 // | |
747 // | ... |
748 // +---------------------------------+ <-- [SP + 96]
749 // | Saved x11(arg1), as |
750 // | __hwasan_check_* clobbers it. |
751 // +---------------------------------+ <-- [SP + 88]
752 // | Saved x10(arg0), as |
753 // | __hwasan_check_* clobbers it. |
754 // +---------------------------------+ <-- [SP + 80]
755 // | |
756 // | Stack frame space for x9. |
757 // +---------------------------------+ <-- [SP + 72]
758 // | |
759 // | Saved x8(fp), as |
760 // | __hwasan_check_* clobbers it. |
761 // +---------------------------------+ <-- [SP + 64]
762 // | ... |
763 // | |
764 // | Stack frame space for x2 - x7. |
765 // | |
766 // | ... |
767 // +---------------------------------+ <-- [SP + 16]
768 // | Return address (x1) for caller |
769 // | of __hwasan_check_*. |
770 // +---------------------------------+ <-- [SP + 8]
771 // | Reserved place for x0, possibly |
772 // | junk, since we don't save it. |
773 // +---------------------------------+ <-- [x2 / SP]
774
775 // Adjust sp
776 OutStreamer->emitInstruction(Inst: MCInstBuilder(RISCV::ADDI)
777 .addReg(Reg: RISCV::X2)
778 .addReg(Reg: RISCV::X2)
779 .addImm(Val: -256),
780 STI: MCSTI);
781
782 // store x10(arg0) by new sp
783 OutStreamer->emitInstruction(Inst: MCInstBuilder(RISCV::SD)
784 .addReg(Reg: RISCV::X10)
785 .addReg(Reg: RISCV::X2)
786 .addImm(Val: 8 * 10),
787 STI: MCSTI);
788 // store x11(arg1) by new sp
789 OutStreamer->emitInstruction(Inst: MCInstBuilder(RISCV::SD)
790 .addReg(Reg: RISCV::X11)
791 .addReg(Reg: RISCV::X2)
792 .addImm(Val: 8 * 11),
793 STI: MCSTI);
794
795 // store x8(fp) by new sp
796 OutStreamer->emitInstruction(
797 Inst: MCInstBuilder(RISCV::SD).addReg(Reg: RISCV::X8).addReg(Reg: RISCV::X2).addImm(Val: 8 *
798 8),
799 STI: MCSTI);
800 // store x1(ra) by new sp
801 OutStreamer->emitInstruction(
802 Inst: MCInstBuilder(RISCV::SD).addReg(Reg: RISCV::X1).addReg(Reg: RISCV::X2).addImm(Val: 1 *
803 8),
804 STI: MCSTI);
805 if (Reg != RISCV::X10)
806 OutStreamer->emitInstruction(Inst: MCInstBuilder(RISCV::ADDI)
807 .addReg(Reg: RISCV::X10)
808 .addReg(Reg)
809 .addImm(Val: 0),
810 STI: MCSTI);
811 OutStreamer->emitInstruction(
812 Inst: MCInstBuilder(RISCV::ADDI)
813 .addReg(Reg: RISCV::X11)
814 .addReg(Reg: RISCV::X0)
815 .addImm(Val: AccessInfo & HWASanAccessInfo::RuntimeMask),
816 STI: MCSTI);
817
818 OutStreamer->emitInstruction(Inst: MCInstBuilder(RISCV::PseudoCALL).addExpr(Val: Expr),
819 STI: MCSTI);
820 }
821}
822
823static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
824 const AsmPrinter &AP) {
825 MCContext &Ctx = AP.OutContext;
826 RISCVMCExpr::VariantKind Kind;
827
828 switch (MO.getTargetFlags()) {
829 default:
830 llvm_unreachable("Unknown target flag on GV operand");
831 case RISCVII::MO_None:
832 Kind = RISCVMCExpr::VK_RISCV_None;
833 break;
834 case RISCVII::MO_CALL:
835 Kind = RISCVMCExpr::VK_RISCV_CALL_PLT;
836 break;
837 case RISCVII::MO_LO:
838 Kind = RISCVMCExpr::VK_RISCV_LO;
839 break;
840 case RISCVII::MO_HI:
841 Kind = RISCVMCExpr::VK_RISCV_HI;
842 break;
843 case RISCVII::MO_PCREL_LO:
844 Kind = RISCVMCExpr::VK_RISCV_PCREL_LO;
845 break;
846 case RISCVII::MO_PCREL_HI:
847 Kind = RISCVMCExpr::VK_RISCV_PCREL_HI;
848 break;
849 case RISCVII::MO_GOT_HI:
850 Kind = RISCVMCExpr::VK_RISCV_GOT_HI;
851 break;
852 case RISCVII::MO_TPREL_LO:
853 Kind = RISCVMCExpr::VK_RISCV_TPREL_LO;
854 break;
855 case RISCVII::MO_TPREL_HI:
856 Kind = RISCVMCExpr::VK_RISCV_TPREL_HI;
857 break;
858 case RISCVII::MO_TPREL_ADD:
859 Kind = RISCVMCExpr::VK_RISCV_TPREL_ADD;
860 break;
861 case RISCVII::MO_TLS_GOT_HI:
862 Kind = RISCVMCExpr::VK_RISCV_TLS_GOT_HI;
863 break;
864 case RISCVII::MO_TLS_GD_HI:
865 Kind = RISCVMCExpr::VK_RISCV_TLS_GD_HI;
866 break;
867 case RISCVII::MO_TLSDESC_HI:
868 Kind = RISCVMCExpr::VK_RISCV_TLSDESC_HI;
869 break;
870 case RISCVII::MO_TLSDESC_LOAD_LO:
871 Kind = RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO;
872 break;
873 case RISCVII::MO_TLSDESC_ADD_LO:
874 Kind = RISCVMCExpr::VK_RISCV_TLSDESC_ADD_LO;
875 break;
876 case RISCVII::MO_TLSDESC_CALL:
877 Kind = RISCVMCExpr::VK_RISCV_TLSDESC_CALL;
878 break;
879 }
880
881 const MCExpr *ME =
882 MCSymbolRefExpr::create(Symbol: Sym, Kind: MCSymbolRefExpr::VK_None, Ctx);
883
884 if (!MO.isJTI() && !MO.isMBB() && MO.getOffset())
885 ME = MCBinaryExpr::createAdd(
886 LHS: ME, RHS: MCConstantExpr::create(Value: MO.getOffset(), Ctx), Ctx);
887
888 if (Kind != RISCVMCExpr::VK_RISCV_None)
889 ME = RISCVMCExpr::create(Expr: ME, Kind, Ctx);
890 return MCOperand::createExpr(Val: ME);
891}
892
893bool RISCVAsmPrinter::lowerOperand(const MachineOperand &MO,
894 MCOperand &MCOp) const {
895 switch (MO.getType()) {
896 default:
897 report_fatal_error(reason: "lowerOperand: unknown operand type");
898 case MachineOperand::MO_Register:
899 // Ignore all implicit register operands.
900 if (MO.isImplicit())
901 return false;
902 MCOp = MCOperand::createReg(Reg: MO.getReg());
903 break;
904 case MachineOperand::MO_RegisterMask:
905 // Regmasks are like implicit defs.
906 return false;
907 case MachineOperand::MO_Immediate:
908 MCOp = MCOperand::createImm(Val: MO.getImm());
909 break;
910 case MachineOperand::MO_MachineBasicBlock:
911 MCOp = lowerSymbolOperand(MO, Sym: MO.getMBB()->getSymbol(), AP: *this);
912 break;
913 case MachineOperand::MO_GlobalAddress:
914 MCOp = lowerSymbolOperand(MO, Sym: getSymbolPreferLocal(GV: *MO.getGlobal()), AP: *this);
915 break;
916 case MachineOperand::MO_BlockAddress:
917 MCOp = lowerSymbolOperand(MO, Sym: GetBlockAddressSymbol(BA: MO.getBlockAddress()),
918 AP: *this);
919 break;
920 case MachineOperand::MO_ExternalSymbol:
921 MCOp = lowerSymbolOperand(MO, Sym: GetExternalSymbolSymbol(Sym: MO.getSymbolName()),
922 AP: *this);
923 break;
924 case MachineOperand::MO_ConstantPoolIndex:
925 MCOp = lowerSymbolOperand(MO, Sym: GetCPISymbol(CPID: MO.getIndex()), AP: *this);
926 break;
927 case MachineOperand::MO_JumpTableIndex:
928 MCOp = lowerSymbolOperand(MO, Sym: GetJTISymbol(JTID: MO.getIndex()), AP: *this);
929 break;
930 case MachineOperand::MO_MCSymbol:
931 MCOp = lowerSymbolOperand(MO, Sym: MO.getMCSymbol(), AP: *this);
932 break;
933 }
934 return true;
935}
936
937static bool lowerRISCVVMachineInstrToMCInst(const MachineInstr *MI,
938 MCInst &OutMI) {
939 const RISCVVPseudosTable::PseudoInfo *RVV =
940 RISCVVPseudosTable::getPseudoInfo(Pseudo: MI->getOpcode());
941 if (!RVV)
942 return false;
943
944 OutMI.setOpcode(RVV->BaseInstr);
945
946 const MachineBasicBlock *MBB = MI->getParent();
947 assert(MBB && "MI expected to be in a basic block");
948 const MachineFunction *MF = MBB->getParent();
949 assert(MF && "MBB expected to be in a machine function");
950
951 const RISCVSubtarget &Subtarget = MF->getSubtarget<RISCVSubtarget>();
952 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
953 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
954 assert(TRI && "TargetRegisterInfo expected");
955
956 const MCInstrDesc &MCID = MI->getDesc();
957 uint64_t TSFlags = MCID.TSFlags;
958 unsigned NumOps = MI->getNumExplicitOperands();
959
960 // Skip policy, SEW, VL, VXRM/FRM operands which are the last operands if
961 // present.
962 if (RISCVII::hasVecPolicyOp(TSFlags))
963 --NumOps;
964 if (RISCVII::hasSEWOp(TSFlags))
965 --NumOps;
966 if (RISCVII::hasVLOp(TSFlags))
967 --NumOps;
968 if (RISCVII::hasRoundModeOp(TSFlags))
969 --NumOps;
970
971 bool hasVLOutput = RISCV::isFaultFirstLoad(MI: *MI);
972 for (unsigned OpNo = 0; OpNo != NumOps; ++OpNo) {
973 const MachineOperand &MO = MI->getOperand(i: OpNo);
974 // Skip vl ouput. It should be the second output.
975 if (hasVLOutput && OpNo == 1)
976 continue;
977
978 // Skip merge op. It should be the first operand after the defs.
979 if (OpNo == MI->getNumExplicitDefs() && MO.isReg() && MO.isTied()) {
980 assert(MCID.getOperandConstraint(OpNo, MCOI::TIED_TO) == 0 &&
981 "Expected tied to first def.");
982 const MCInstrDesc &OutMCID = TII->get(Opcode: OutMI.getOpcode());
983 // Skip if the next operand in OutMI is not supposed to be tied. Unless it
984 // is a _TIED instruction.
985 if (OutMCID.getOperandConstraint(OpNum: OutMI.getNumOperands(), Constraint: MCOI::TIED_TO) <
986 0 &&
987 !RISCVII::isTiedPseudo(TSFlags))
988 continue;
989 }
990
991 MCOperand MCOp;
992 switch (MO.getType()) {
993 default:
994 llvm_unreachable("Unknown operand type");
995 case MachineOperand::MO_Register: {
996 Register Reg = MO.getReg();
997
998 if (RISCV::VRM2RegClass.contains(Reg) ||
999 RISCV::VRM4RegClass.contains(Reg) ||
1000 RISCV::VRM8RegClass.contains(Reg)) {
1001 Reg = TRI->getSubReg(Reg, Idx: RISCV::sub_vrm1_0);
1002 assert(Reg && "Subregister does not exist");
1003 } else if (RISCV::FPR16RegClass.contains(Reg)) {
1004 Reg =
1005 TRI->getMatchingSuperReg(Reg, SubIdx: RISCV::sub_16, RC: &RISCV::FPR32RegClass);
1006 assert(Reg && "Subregister does not exist");
1007 } else if (RISCV::FPR64RegClass.contains(Reg)) {
1008 Reg = TRI->getSubReg(Reg, Idx: RISCV::sub_32);
1009 assert(Reg && "Superregister does not exist");
1010 } else if (RISCV::VRN2M1RegClass.contains(Reg) ||
1011 RISCV::VRN2M2RegClass.contains(Reg) ||
1012 RISCV::VRN2M4RegClass.contains(Reg) ||
1013 RISCV::VRN3M1RegClass.contains(Reg) ||
1014 RISCV::VRN3M2RegClass.contains(Reg) ||
1015 RISCV::VRN4M1RegClass.contains(Reg) ||
1016 RISCV::VRN4M2RegClass.contains(Reg) ||
1017 RISCV::VRN5M1RegClass.contains(Reg) ||
1018 RISCV::VRN6M1RegClass.contains(Reg) ||
1019 RISCV::VRN7M1RegClass.contains(Reg) ||
1020 RISCV::VRN8M1RegClass.contains(Reg)) {
1021 Reg = TRI->getSubReg(Reg, Idx: RISCV::sub_vrm1_0);
1022 assert(Reg && "Subregister does not exist");
1023 }
1024
1025 MCOp = MCOperand::createReg(Reg);
1026 break;
1027 }
1028 case MachineOperand::MO_Immediate:
1029 MCOp = MCOperand::createImm(Val: MO.getImm());
1030 break;
1031 }
1032 OutMI.addOperand(Op: MCOp);
1033 }
1034
1035 // Unmasked pseudo instructions need to append dummy mask operand to
1036 // V instructions. All V instructions are modeled as the masked version.
1037 const MCInstrDesc &OutMCID = TII->get(Opcode: OutMI.getOpcode());
1038 if (OutMI.getNumOperands() < OutMCID.getNumOperands()) {
1039 assert(OutMCID.operands()[OutMI.getNumOperands()].RegClass ==
1040 RISCV::VMV0RegClassID &&
1041 "Expected only mask operand to be missing");
1042 OutMI.addOperand(Op: MCOperand::createReg(Reg: RISCV::NoRegister));
1043 }
1044
1045 assert(OutMI.getNumOperands() == OutMCID.getNumOperands());
1046 return true;
1047}
1048
1049bool RISCVAsmPrinter::lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) {
1050 if (lowerRISCVVMachineInstrToMCInst(MI, OutMI))
1051 return false;
1052
1053 OutMI.setOpcode(MI->getOpcode());
1054
1055 for (const MachineOperand &MO : MI->operands()) {
1056 MCOperand MCOp;
1057 if (lowerOperand(MO, MCOp))
1058 OutMI.addOperand(Op: MCOp);
1059 }
1060
1061 switch (OutMI.getOpcode()) {
1062 case TargetOpcode::PATCHABLE_FUNCTION_ENTER: {
1063 const Function &F = MI->getParent()->getParent()->getFunction();
1064 if (F.hasFnAttribute(Kind: "patchable-function-entry")) {
1065 unsigned Num;
1066 if (F.getFnAttribute(Kind: "patchable-function-entry")
1067 .getValueAsString()
1068 .getAsInteger(Radix: 10, Result&: Num))
1069 return false;
1070 emitNops(N: Num);
1071 return true;
1072 }
1073 break;
1074 }
1075 }
1076 return false;
1077}
1078