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/RISCVELFStreamer.h"
16#include "MCTargetDesc/RISCVInstPrinter.h"
17#include "MCTargetDesc/RISCVMCAsmInfo.h"
18#include "MCTargetDesc/RISCVMatInt.h"
19#include "MCTargetDesc/RISCVTargetStreamer.h"
20#include "RISCV.h"
21#include "RISCVConstantPoolValue.h"
22#include "RISCVMachineFunctionInfo.h"
23#include "RISCVRegisterInfo.h"
24#include "TargetInfo/RISCVTargetInfo.h"
25#include "llvm/ADT/APInt.h"
26#include "llvm/ADT/Statistic.h"
27#include "llvm/BinaryFormat/ELF.h"
28#include "llvm/CodeGen/AsmPrinter.h"
29#include "llvm/CodeGen/MachineConstantPool.h"
30#include "llvm/CodeGen/MachineInstr.h"
31#include "llvm/CodeGen/MachineModuleInfo.h"
32#include "llvm/IR/Module.h"
33#include "llvm/MC/MCAsmInfo.h"
34#include "llvm/MC/MCContext.h"
35#include "llvm/MC/MCInst.h"
36#include "llvm/MC/MCInstBuilder.h"
37#include "llvm/MC/MCObjectFileInfo.h"
38#include "llvm/MC/MCSectionELF.h"
39#include "llvm/MC/MCStreamer.h"
40#include "llvm/MC/MCSymbol.h"
41#include "llvm/MC/TargetRegistry.h"
42#include "llvm/Support/Compiler.h"
43#include "llvm/Support/raw_ostream.h"
44#include "llvm/TargetParser/RISCVISAInfo.h"
45#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
46
47using namespace llvm;
48
49#define DEBUG_TYPE "asm-printer"
50
51STATISTIC(RISCVNumInstrsCompressed,
52 "Number of RISC-V Compressed instructions emitted");
53
54namespace {
55class RISCVAsmPrinter : public AsmPrinter {
56public:
57 static char ID;
58
59private:
60 const RISCVSubtarget *STI;
61
62public:
63 explicit RISCVAsmPrinter(TargetMachine &TM,
64 std::unique_ptr<MCStreamer> Streamer)
65 : AsmPrinter(TM, std::move(Streamer), ID) {}
66
67 StringRef getPassName() const override { return "RISC-V Assembly Printer"; }
68
69 RISCVTargetStreamer &getTargetStreamer() const {
70 return static_cast<RISCVTargetStreamer &>(
71 *OutStreamer->getTargetStreamer());
72 }
73
74 void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
75 const MachineInstr &MI);
76
77 void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
78 const MachineInstr &MI);
79
80 void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
81 const MachineInstr &MI);
82
83 bool runOnMachineFunction(MachineFunction &MF) override;
84
85 void emitInstruction(const MachineInstr *MI) override;
86
87 void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override;
88
89 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
90 const char *ExtraCode, raw_ostream &OS) override;
91 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
92 const char *ExtraCode, raw_ostream &OS) override;
93
94 // Returns whether Inst is compressed.
95 bool EmitToStreamer(MCStreamer &S, const MCInst &Inst,
96 const MCSubtargetInfo &SubtargetInfo);
97 bool EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
98 return EmitToStreamer(S, Inst, SubtargetInfo: *STI);
99 }
100
101 bool lowerPseudoInstExpansion(const MachineInstr *MI, MCInst &Inst);
102
103 typedef std::tuple<unsigned, uint32_t> HwasanMemaccessTuple;
104 std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
105 void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
106 void LowerKCFI_CHECK(const MachineInstr &MI);
107 void EmitHwasanMemaccessSymbols(Module &M);
108
109 // Wrapper needed for tblgenned pseudo lowering.
110 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const;
111
112 void emitStartOfAsmFile(Module &M) override;
113 void emitEndOfAsmFile(Module &M) override;
114
115 void emitFunctionEntryLabel() override;
116 bool emitDirectiveOptionArch();
117
118 void emitNoteGnuProperty(const Module &M);
119
120private:
121 void emitAttributes(const MCSubtargetInfo &SubtargetInfo);
122
123 void emitNTLHint(const MachineInstr *MI);
124
125 void emitLpadAlignedCall(const MachineInstr &MI);
126
127 // XRay Support
128 void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr *MI);
129 void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr *MI);
130 void LowerPATCHABLE_TAIL_CALL(const MachineInstr *MI);
131 void emitSled(const MachineInstr *MI, SledKind Kind);
132
133 void lowerToMCInst(const MachineInstr *MI, MCInst &OutMI);
134};
135} // namespace
136
137void RISCVAsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
138 const MachineInstr &MI) {
139 unsigned NOPBytes = STI->hasStdExtZca() ? 2 : 4;
140 unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();
141
142 auto &Ctx = OutStreamer.getContext();
143 MCSymbol *MILabel = Ctx.createTempSymbol();
144 OutStreamer.emitLabel(Symbol: MILabel);
145
146 SM.recordStackMap(L: *MILabel, MI);
147 assert(NumNOPBytes % NOPBytes == 0 &&
148 "Invalid number of NOP bytes requested!");
149
150 // Scan ahead to trim the shadow.
151 const MachineBasicBlock &MBB = *MI.getParent();
152 MachineBasicBlock::const_iterator MII(MI);
153 ++MII;
154 while (NumNOPBytes > 0) {
155 if (MII == MBB.end() || MII->isCall() ||
156 MII->getOpcode() == RISCV::DBG_VALUE ||
157 MII->getOpcode() == TargetOpcode::PATCHPOINT ||
158 MII->getOpcode() == TargetOpcode::STACKMAP)
159 break;
160 ++MII;
161 NumNOPBytes -= NOPBytes;
162 }
163
164 // Emit nops.
165 emitNops(N: NumNOPBytes / NOPBytes);
166}
167
168// Lower a patchpoint of the form:
169// [<def>], <id>, <numBytes>, <target>, <numArgs>
170void RISCVAsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
171 const MachineInstr &MI) {
172 unsigned NOPBytes = STI->hasStdExtZca() ? 2 : 4;
173
174 auto &Ctx = OutStreamer.getContext();
175 MCSymbol *MILabel = Ctx.createTempSymbol();
176 OutStreamer.emitLabel(Symbol: MILabel);
177 SM.recordPatchPoint(L: *MILabel, MI);
178
179 PatchPointOpers Opers(&MI);
180
181 const MachineOperand &CalleeMO = Opers.getCallTarget();
182 unsigned EncodedBytes = 0;
183
184 if (CalleeMO.isImm()) {
185 uint64_t CallTarget = CalleeMO.getImm();
186 if (CallTarget) {
187 assert((CallTarget & 0xFFFF'FFFF'FFFF) == CallTarget &&
188 "High 16 bits of call target should be zero.");
189 // Materialize the jump address:
190 SmallVector<MCInst, 8> Seq;
191 RISCVMatInt::generateMCInstSeq(Val: CallTarget, STI: *STI, DestReg: RISCV::X1, Insts&: Seq);
192 for (MCInst &Inst : Seq) {
193 bool Compressed = EmitToStreamer(S&: OutStreamer, Inst);
194 EncodedBytes += Compressed ? 2 : 4;
195 }
196 bool Compressed = EmitToStreamer(S&: OutStreamer, Inst: MCInstBuilder(RISCV::JALR)
197 .addReg(Reg: RISCV::X1)
198 .addReg(Reg: RISCV::X1)
199 .addImm(Val: 0));
200 EncodedBytes += Compressed ? 2 : 4;
201 }
202 } else if (CalleeMO.isGlobal()) {
203 MCOperand CallTargetMCOp;
204 lowerOperand(MO: CalleeMO, MCOp&: CallTargetMCOp);
205 EmitToStreamer(S&: OutStreamer,
206 Inst: MCInstBuilder(RISCV::PseudoCALL).addOperand(Op: CallTargetMCOp));
207 EncodedBytes += 8;
208 }
209
210 // Emit padding.
211 unsigned NumBytes = Opers.getNumPatchBytes();
212 assert(NumBytes >= EncodedBytes &&
213 "Patchpoint can't request size less than the length of a call.");
214 assert((NumBytes - EncodedBytes) % NOPBytes == 0 &&
215 "Invalid number of NOP bytes requested!");
216 emitNops(N: (NumBytes - EncodedBytes) / NOPBytes);
217}
218
219void RISCVAsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
220 const MachineInstr &MI) {
221 unsigned NOPBytes = STI->hasStdExtZca() ? 2 : 4;
222
223 StatepointOpers SOpers(&MI);
224 if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
225 assert(PatchBytes % NOPBytes == 0 &&
226 "Invalid number of NOP bytes requested!");
227 emitNops(N: PatchBytes / NOPBytes);
228 } else {
229 // Lower call target and choose correct opcode
230 const MachineOperand &CallTarget = SOpers.getCallTarget();
231 MCOperand CallTargetMCOp;
232 switch (CallTarget.getType()) {
233 case MachineOperand::MO_GlobalAddress:
234 case MachineOperand::MO_ExternalSymbol:
235 lowerOperand(MO: CallTarget, MCOp&: CallTargetMCOp);
236 EmitToStreamer(
237 S&: OutStreamer,
238 Inst: MCInstBuilder(RISCV::PseudoCALL).addOperand(Op: CallTargetMCOp));
239 break;
240 case MachineOperand::MO_Immediate:
241 CallTargetMCOp = MCOperand::createImm(Val: CallTarget.getImm());
242 EmitToStreamer(S&: OutStreamer, Inst: MCInstBuilder(RISCV::JAL)
243 .addReg(Reg: RISCV::X1)
244 .addOperand(Op: CallTargetMCOp));
245 break;
246 case MachineOperand::MO_Register:
247 CallTargetMCOp = MCOperand::createReg(Reg: CallTarget.getReg());
248 EmitToStreamer(S&: OutStreamer, Inst: MCInstBuilder(RISCV::JALR)
249 .addReg(Reg: RISCV::X1)
250 .addOperand(Op: CallTargetMCOp)
251 .addImm(Val: 0));
252 break;
253 default:
254 llvm_unreachable("Unsupported operand type in statepoint call target");
255 break;
256 }
257 }
258
259 auto &Ctx = OutStreamer.getContext();
260 MCSymbol *MILabel = Ctx.createTempSymbol();
261 OutStreamer.emitLabel(Symbol: MILabel);
262 SM.recordStatepoint(L: *MILabel, MI);
263}
264
265bool RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst,
266 const MCSubtargetInfo &SubtargetInfo) {
267 MCInst CInst;
268 bool Res = RISCVRVC::compress(OutInst&: CInst, MI: Inst, STI: SubtargetInfo);
269 if (Res)
270 ++RISCVNumInstrsCompressed;
271 S.emitInstruction(Inst: Res ? CInst : Inst, STI: SubtargetInfo);
272 return Res;
273}
274
275// Simple pseudo-instructions have their lowering (with expansion to real
276// instructions) auto-generated.
277#include "RISCVGenMCPseudoLowering.inc"
278
279// Emit a call to a returns_twice function with LPAD.
280// When Zca is enabled, emit .p2align 2 before the call to ensure the
281// following LPAD is 4-byte aligned. For assembly output, wrap with
282// .option push/exact/pop to prevent relaxation. For object output,
283// emit the pseudo directly so MCCodeEmitter handles it without R_RISCV_RELAX.
284void RISCVAsmPrinter::emitLpadAlignedCall(const MachineInstr &MI) {
285 const MCSubtargetInfo &MCSTI = getSubtargetInfo();
286 const bool IsIndirect = MI.getOpcode() == RISCV::PseudoCALLIndirectLpadAlign,
287 HasZca = MCSTI.hasFeature(Feature: RISCV::FeatureStdExtZca),
288 HasRelax = MCSTI.hasFeature(Feature: RISCV::FeatureRelax);
289
290 if (HasZca)
291 OutStreamer->emitCodeAlignment(Alignment: Align(4), STI: MCSTI);
292
293 if (OutStreamer->hasRawTextSupport()) {
294 // Assembly path: wrap call with .option push/exact/pop and emit LPAD
295 // separately so the output is human-readable.
296 RISCVTargetStreamer &RTS = getTargetStreamer();
297 if (HasZca && HasRelax) {
298 RTS.emitDirectiveOptionPush();
299 RTS.emitDirectiveOptionExact();
300 }
301
302 MCInst CallInst;
303 if (!IsIndirect) {
304 MCOperand MCOp;
305 lowerOperand(MO: MI.getOperand(i: 0), MCOp);
306 CallInst = MCInstBuilder(RISCV::PseudoCALL).addOperand(Op: MCOp);
307 } else {
308 CallInst = MCInstBuilder(RISCV::JALR)
309 .addReg(Reg: RISCV::X1)
310 .addReg(Reg: MI.getOperand(i: 0).getReg())
311 .addImm(Val: 0);
312 }
313
314 if (HasZca && HasRelax) {
315 MCSubtargetInfo NoRelaxSTI(MCSTI);
316 NoRelaxSTI.ToggleFeature(FB: RISCV::FeatureRelax);
317 EmitToStreamer(S&: *OutStreamer, Inst: CallInst, SubtargetInfo: NoRelaxSTI);
318 RTS.emitDirectiveOptionPop();
319 } else {
320 EmitToStreamer(S&: *OutStreamer, Inst: CallInst, SubtargetInfo: MCSTI);
321 }
322
323 // LPAD is encoded as AUIPC X0, label.
324 MCInst LpadInst = MCInstBuilder(RISCV::AUIPC)
325 .addReg(Reg: RISCV::X0)
326 .addImm(Val: MI.getOperand(i: 1).getImm());
327 EmitToStreamer(S&: *OutStreamer, Inst: LpadInst, SubtargetInfo: MCSTI);
328 } else {
329 // Object path: emit PseudoCALL(Indirect)LpadAlign directly.
330 // MCCodeEmitter::expandFunctionCallLpad expands to AUIPC+JALR+LPAD
331 // without emitting R_RISCV_RELAX on the call fixup.
332 MCInst TmpInst;
333 TmpInst.setOpcode(MI.getOpcode());
334 if (!IsIndirect) {
335 MCOperand MCOp;
336 lowerOperand(MO: MI.getOperand(i: 0), MCOp);
337 TmpInst.addOperand(Op: MCOp);
338 } else {
339 TmpInst.addOperand(Op: MCOperand::createReg(Reg: MI.getOperand(i: 0).getReg()));
340 }
341 TmpInst.addOperand(Op: MCOperand::createImm(Val: MI.getOperand(i: 1).getImm()));
342 EmitToStreamer(S&: *OutStreamer, Inst: TmpInst, SubtargetInfo: MCSTI);
343 }
344}
345
346// If the instruction has a nontemporal MachineMemOperand, emit an NTL hint
347// instruction before it. NTL hints are always safe to emit since they use
348// HINT encodings that are guaranteed not to trap
349// (riscv-non-isa/riscv-elf-psabi-doc#474).
350void RISCVAsmPrinter::emitNTLHint(const MachineInstr *MI) {
351 if (!STI->getInstrInfo()->requiresNTLHint(MI: *MI))
352 return;
353
354 assert(!MI->memoperands_empty());
355
356 MachineMemOperand *MMO = *(MI->memoperands_begin());
357
358 assert(MMO->isNonTemporal());
359
360 unsigned NontemporalMode = 0;
361 if (MMO->getFlags() & MONontemporalBit0)
362 NontemporalMode += 0b1;
363 if (MMO->getFlags() & MONontemporalBit1)
364 NontemporalMode += 0b10;
365
366 MCInst Hint;
367 if (STI->hasStdExtZca())
368 Hint.setOpcode(RISCV::C_ADD);
369 else
370 Hint.setOpcode(RISCV::ADD);
371
372 Hint.addOperand(Op: MCOperand::createReg(Reg: RISCV::X0));
373 Hint.addOperand(Op: MCOperand::createReg(Reg: RISCV::X0));
374 Hint.addOperand(Op: MCOperand::createReg(Reg: RISCV::X2 + NontemporalMode));
375
376 EmitToStreamer(S&: *OutStreamer, Inst: Hint);
377}
378
379void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) {
380 RISCV_MC::verifyInstructionPredicates(Opcode: MI->getOpcode(), Features: STI->getFeatureBits());
381
382 emitNTLHint(MI);
383
384 // Do any auto-generated pseudo lowerings.
385 if (MCInst OutInst; lowerPseudoInstExpansion(MI, Inst&: OutInst)) {
386 EmitToStreamer(S&: *OutStreamer, Inst: OutInst);
387 return;
388 }
389
390 switch (MI->getOpcode()) {
391 case RISCV::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
392 LowerHWASAN_CHECK_MEMACCESS(MI: *MI);
393 return;
394 case RISCV::KCFI_CHECK:
395 LowerKCFI_CHECK(MI: *MI);
396 return;
397 case TargetOpcode::STACKMAP:
398 return LowerSTACKMAP(OutStreamer&: *OutStreamer, SM, MI: *MI);
399 case TargetOpcode::PATCHPOINT:
400 return LowerPATCHPOINT(OutStreamer&: *OutStreamer, SM, MI: *MI);
401 case TargetOpcode::STATEPOINT:
402 return LowerSTATEPOINT(OutStreamer&: *OutStreamer, SM, MI: *MI);
403 case TargetOpcode::PATCHABLE_FUNCTION_ENTER: {
404 const Function &F = MI->getParent()->getParent()->getFunction();
405 if (F.hasFnAttribute(Kind: "patchable-function-entry")) {
406 unsigned Num =
407 F.getFnAttributeAsParsedInteger(Kind: "patchable-function-entry");
408 emitNops(N: Num);
409 return;
410 }
411 LowerPATCHABLE_FUNCTION_ENTER(MI);
412 return;
413 }
414 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
415 LowerPATCHABLE_FUNCTION_EXIT(MI);
416 return;
417 case TargetOpcode::PATCHABLE_TAIL_CALL:
418 LowerPATCHABLE_TAIL_CALL(MI);
419 return;
420 case RISCV::PseudoCALLLpadAlign:
421 case RISCV::PseudoCALLIndirectLpadAlign:
422 emitLpadAlignedCall(MI: *MI);
423 return;
424 }
425
426 MCInst OutInst;
427 lowerToMCInst(MI, OutMI&: OutInst);
428 EmitToStreamer(S&: *OutStreamer, Inst: OutInst);
429}
430
431bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
432 const char *ExtraCode, raw_ostream &OS) {
433 // First try the generic code, which knows about modifiers like 'c' and 'n'.
434 if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
435 return false;
436
437 const MachineOperand &MO = MI->getOperand(i: OpNo);
438 if (ExtraCode && ExtraCode[0]) {
439 if (ExtraCode[1] != 0)
440 return true; // Unknown modifier.
441
442 switch (ExtraCode[0]) {
443 default:
444 return true; // Unknown modifier.
445 case 'z': // Print zero register if zero, regular printing otherwise.
446 if (MO.isImm() && MO.getImm() == 0) {
447 OS << RISCVInstPrinter::getRegisterName(Reg: RISCV::X0);
448 return false;
449 }
450 break;
451 case 'i': // Literal 'i' if operand is not a register.
452 if (!MO.isReg())
453 OS << 'i';
454 return false;
455 case 'N': // Print the register encoding as an integer (0-31)
456 if (!MO.isReg())
457 return true;
458
459 const RISCVRegisterInfo *TRI = STI->getRegisterInfo();
460 OS << TRI->getEncodingValue(Reg: MO.getReg());
461 return false;
462 }
463 }
464
465 switch (MO.getType()) {
466 case MachineOperand::MO_Immediate:
467 OS << MO.getImm();
468 return false;
469 case MachineOperand::MO_Register:
470 OS << RISCVInstPrinter::getRegisterName(Reg: MO.getReg());
471 return false;
472 case MachineOperand::MO_GlobalAddress:
473 PrintSymbolOperand(MO, OS);
474 return false;
475 case MachineOperand::MO_BlockAddress: {
476 MCSymbol *Sym = GetBlockAddressSymbol(BA: MO.getBlockAddress());
477 Sym->print(OS, MAI);
478 return false;
479 }
480 default:
481 break;
482 }
483
484 return true;
485}
486
487bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
488 unsigned OpNo,
489 const char *ExtraCode,
490 raw_ostream &OS) {
491 if (ExtraCode)
492 return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
493
494 const MachineOperand &AddrReg = MI->getOperand(i: OpNo);
495 assert(MI->getNumOperands() > OpNo + 1 && "Expected additional operand");
496 const MachineOperand &Offset = MI->getOperand(i: OpNo + 1);
497 // All memory operands should have a register and an immediate operand (see
498 // RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand).
499 if (!AddrReg.isReg())
500 return true;
501 if (!Offset.isImm() && !Offset.isGlobal() && !Offset.isBlockAddress() &&
502 !Offset.isMCSymbol())
503 return true;
504
505 MCOperand MCO;
506 if (!lowerOperand(MO: Offset, MCOp&: MCO))
507 return true;
508
509 if (Offset.isImm())
510 OS << MCO.getImm();
511 else if (Offset.isGlobal() || Offset.isBlockAddress() || Offset.isMCSymbol())
512 MAI.printExpr(OS, *MCO.getExpr());
513
514 if (Offset.isMCSymbol())
515 MMI->getContext().registerInlineAsmLabel(Sym: Offset.getMCSymbol());
516 if (Offset.isBlockAddress()) {
517 const BlockAddress *BA = Offset.getBlockAddress();
518 MCSymbol *Sym = GetBlockAddressSymbol(BA);
519 MMI->getContext().registerInlineAsmLabel(Sym);
520 }
521
522 OS << "(" << RISCVInstPrinter::getRegisterName(Reg: AddrReg.getReg()) << ")";
523 return false;
524}
525
526bool RISCVAsmPrinter::emitDirectiveOptionArch() {
527 RISCVTargetStreamer &RTS = getTargetStreamer();
528 SmallVector<RISCVOptionArchArg> NeedEmitStdOptionArgs;
529 const MCSubtargetInfo &MCSTI = TM.getMCSubtargetInfo();
530 for (const auto &Feature : MCSTI.getAllProcessorFeatures()) {
531 if (STI->hasFeature(Feature: Feature.Value) == MCSTI.hasFeature(Feature: Feature.Value))
532 continue;
533
534 if (!llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext: Feature.key()))
535 continue;
536
537 auto Delta = STI->hasFeature(Feature: Feature.Value) ? RISCVOptionArchArgType::Plus
538 : RISCVOptionArchArgType::Minus;
539 StringRef ExtName = Feature.key();
540 ExtName.consume_front(Prefix: "experimental-");
541 NeedEmitStdOptionArgs.emplace_back(Args&: Delta, Args: ExtName.str());
542 }
543 if (!NeedEmitStdOptionArgs.empty()) {
544 RTS.emitDirectiveOptionPush();
545 RTS.emitDirectiveOptionArch(Args: NeedEmitStdOptionArgs);
546 return true;
547 }
548
549 return false;
550}
551
552bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
553 STI = &MF.getSubtarget<RISCVSubtarget>();
554 RISCVTargetStreamer &RTS = getTargetStreamer();
555
556 bool EmittedOptionArch = emitDirectiveOptionArch();
557
558 SetupMachineFunction(MF);
559 emitFunctionBody();
560
561 // Emit the XRay table
562 emitXRayTable();
563
564 if (EmittedOptionArch)
565 RTS.emitDirectiveOptionPop();
566 return false;
567}
568
569void RISCVAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr *MI) {
570 emitSled(MI, Kind: SledKind::FUNCTION_ENTER);
571}
572
573void RISCVAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr *MI) {
574 emitSled(MI, Kind: SledKind::FUNCTION_EXIT);
575}
576
577void RISCVAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr *MI) {
578 emitSled(MI, Kind: SledKind::TAIL_CALL);
579}
580
581void RISCVAsmPrinter::emitSled(const MachineInstr *MI, SledKind Kind) {
582 // We want to emit the jump instruction and the nops constituting the sled.
583 // The format is as follows:
584 // .Lxray_sled_N
585 // ALIGN
586 // J .tmpN
587 // 21 or 33 C.NOP instructions
588 // .tmpN
589
590 // The following variable holds the count of the number of NOPs to be patched
591 // in for XRay instrumentation during compilation.
592 // Note that RV64 and RV32 each has a sled of 68 and 44 bytes, respectively.
593 // Assuming we're using JAL to jump to .tmpN, then we only need
594 // (68 - 4)/2 = 32 NOPs for RV64 and (44 - 4)/2 = 20 for RV32. However, there
595 // is a chance that we'll use C.JAL instead, so an additional NOP is needed.
596 const uint8_t NoopsInSledCount = STI->is64Bit() ? 33 : 21;
597
598 OutStreamer->emitCodeAlignment(Alignment: Align(4), STI: *STI);
599 auto CurSled = OutContext.createTempSymbol(Name: "xray_sled_", AlwaysAddSuffix: true);
600 OutStreamer->emitLabel(Symbol: CurSled);
601 auto Target = OutContext.createTempSymbol();
602
603 const MCExpr *TargetExpr = MCSymbolRefExpr::create(Symbol: Target, Ctx&: OutContext);
604
605 // Emit "J bytes" instruction, which jumps over the nop sled to the actual
606 // start of function.
607 EmitToStreamer(
608 S&: *OutStreamer,
609 Inst: MCInstBuilder(RISCV::JAL).addReg(Reg: RISCV::X0).addExpr(Val: TargetExpr));
610
611 // Emit NOP instructions
612 for (int8_t I = 0; I < NoopsInSledCount; ++I)
613 EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::ADDI)
614 .addReg(Reg: RISCV::X0)
615 .addReg(Reg: RISCV::X0)
616 .addImm(Val: 0));
617
618 OutStreamer->emitLabel(Symbol: Target);
619 recordSled(Sled: CurSled, MI: *MI, Kind, Version: 2);
620}
621
622void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) {
623 assert(OutStreamer->getTargetStreamer() &&
624 "target streamer is uninitialized");
625 RISCVTargetStreamer &RTS = getTargetStreamer();
626 if (const MDString *ModuleTargetABI =
627 dyn_cast_or_null<MDString>(Val: M.getModuleFlag(Key: "target-abi")))
628 RTS.setTargetABI(RISCVABI::getTargetABI(ABIName: ModuleTargetABI->getString()));
629
630 MCSubtargetInfo SubtargetInfo = TM.getMCSubtargetInfo();
631
632 // Use module flag to update feature bits.
633 if (auto *MD = dyn_cast_or_null<MDNode>(Val: M.getModuleFlag(Key: "riscv-isa"))) {
634 for (auto &ISA : MD->operands()) {
635 if (auto *ISAString = dyn_cast_or_null<MDString>(Val: ISA)) {
636 auto ParseResult = llvm::RISCVISAInfo::parseArchString(
637 Arch: ISAString->getString(), /*EnableExperimentalExtension=*/true,
638 /*ExperimentalExtensionVersionCheck=*/true);
639 if (!errorToBool(Err: ParseResult.takeError())) {
640 auto &ISAInfo = *ParseResult;
641 for (const auto &Feature : SubtargetInfo.getAllProcessorFeatures()) {
642 if (ISAInfo->hasExtension(Ext: Feature.key()) &&
643 !SubtargetInfo.hasFeature(Feature: Feature.Value))
644 SubtargetInfo.ToggleFeature(FS: Feature.key());
645 }
646 }
647 }
648 }
649
650 RTS.setFlagsFromFeatures(SubtargetInfo);
651 }
652
653 if (TM.getTargetTriple().isOSBinFormatELF())
654 emitAttributes(SubtargetInfo);
655}
656
657void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) {
658 RISCVTargetStreamer &RTS = getTargetStreamer();
659
660 if (TM.getTargetTriple().isOSBinFormatELF()) {
661 RTS.finishAttributeSection();
662 emitNoteGnuProperty(M);
663 }
664 EmitHwasanMemaccessSymbols(M);
665}
666
667void RISCVAsmPrinter::emitAttributes(const MCSubtargetInfo &SubtargetInfo) {
668 RISCVTargetStreamer &RTS = getTargetStreamer();
669 // Use MCSubtargetInfo from TargetMachine. Individual functions may have
670 // attributes that differ from other functions in the module and we have no
671 // way to know which function is correct.
672 RTS.emitTargetAttributes(STI: SubtargetInfo, /*EmitStackAlign*/ true);
673}
674
675void RISCVAsmPrinter::emitFunctionEntryLabel() {
676 const auto *RMFI = MF->getInfo<RISCVMachineFunctionInfo>();
677 if (RMFI->isVectorCall()) {
678 RISCVTargetStreamer &RTS = getTargetStreamer();
679 RTS.emitDirectiveVariantCC(Symbol&: *CurrentFnSym);
680 }
681 return AsmPrinter::emitFunctionEntryLabel();
682}
683
684// Force static initialization.
685extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
686LLVMInitializeRISCVAsmPrinter() {
687 RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());
688 RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target());
689 RegisterAsmPrinter<RISCVAsmPrinter> A(getTheRISCV32beTarget());
690 RegisterAsmPrinter<RISCVAsmPrinter> B(getTheRISCV64beTarget());
691}
692
693void RISCVAsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
694 Register Reg = MI.getOperand(i: 0).getReg();
695 uint32_t AccessInfo = MI.getOperand(i: 1).getImm();
696 MCSymbol *&Sym =
697 HwasanMemaccessSymbols[HwasanMemaccessTuple(Reg, AccessInfo)];
698 if (!Sym) {
699 // FIXME: Make this work on non-ELF.
700 if (!TM.getTargetTriple().isOSBinFormatELF())
701 report_fatal_error(reason: "llvm.hwasan.check.memaccess only supported on ELF");
702
703 std::string SymName = "__hwasan_check_x" + utostr(X: Reg - RISCV::X0) + "_" +
704 utostr(X: AccessInfo) + "_short";
705 Sym = OutContext.getOrCreateSymbol(Name: SymName);
706 }
707 auto Res = MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext);
708 auto Expr = MCSpecifierExpr::create(Expr: Res, S: RISCV::S_CALL_PLT, Ctx&: OutContext);
709
710 EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::PseudoCALL).addExpr(Val: Expr));
711}
712
713void RISCVAsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
714 Register AddrReg = MI.getOperand(i: 0).getReg();
715 assert(std::next(MI.getIterator())->isCall() &&
716 "KCFI_CHECK not followed by a call instruction");
717 assert(std::next(MI.getIterator())->getOperand(0).getReg() == AddrReg &&
718 "KCFI_CHECK call target doesn't match call operand");
719
720 // Temporary registers for comparing the hashes. If a register is used
721 // for the call target, or reserved by the user, we can clobber another
722 // temporary register as the check is immediately followed by the
723 // call. The check defaults to X6/X7, but can fall back to X28-X31 if
724 // needed.
725 unsigned ScratchRegs[] = {RISCV::X6, RISCV::X7};
726 unsigned NextReg = RISCV::X28;
727 auto isRegAvailable = [&](unsigned Reg) {
728 return Reg != AddrReg && !STI->isRegisterReservedByUser(i: Reg);
729 };
730 for (auto &Reg : ScratchRegs) {
731 if (isRegAvailable(Reg))
732 continue;
733 while (!isRegAvailable(NextReg))
734 ++NextReg;
735 Reg = NextReg++;
736 if (Reg > RISCV::X31)
737 report_fatal_error(reason: "Unable to find scratch registers for KCFI_CHECK");
738 }
739
740 if (AddrReg == RISCV::X0) {
741 // Checking X0 makes no sense. Instead of emitting a load, zero
742 // ScratchRegs[0].
743 EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::ADDI)
744 .addReg(Reg: ScratchRegs[0])
745 .addReg(Reg: RISCV::X0)
746 .addImm(Val: 0));
747 } else {
748 // Adjust the offset for patchable-function-prefix. This assumes that
749 // patchable-function-prefix is the same for all functions.
750 int NopSize = STI->hasStdExtZca() ? 2 : 4;
751 int64_t PrefixNops =
752 MI.getMF()->getFunction().getFnAttributeAsParsedInteger(
753 Kind: "patchable-function-prefix");
754
755 // Load the target function type hash.
756 EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::LW)
757 .addReg(Reg: ScratchRegs[0])
758 .addReg(Reg: AddrReg)
759 .addImm(Val: -(PrefixNops * NopSize + 4)));
760 }
761
762 // Load the expected 32-bit type hash.
763 const int64_t Type = MI.getOperand(i: 1).getImm();
764 const int64_t Hi20 = ((Type + 0x800) >> 12) & 0xFFFFF;
765 const int64_t Lo12 = SignExtend64<12>(x: Type);
766 if (Hi20) {
767 EmitToStreamer(
768 S&: *OutStreamer,
769 Inst: MCInstBuilder(RISCV::LUI).addReg(Reg: ScratchRegs[1]).addImm(Val: Hi20));
770 }
771 if (Lo12 || Hi20 == 0) {
772 EmitToStreamer(S&: *OutStreamer,
773 Inst: MCInstBuilder((STI->hasFeature(Feature: RISCV::Feature64Bit) && Hi20)
774 ? RISCV::ADDIW
775 : RISCV::ADDI)
776 .addReg(Reg: ScratchRegs[1])
777 .addReg(Reg: ScratchRegs[1])
778 .addImm(Val: Lo12));
779 }
780
781 // Compare the hashes and trap if there's a mismatch.
782 MCSymbol *Pass = OutContext.createTempSymbol();
783 EmitToStreamer(S&: *OutStreamer,
784 Inst: MCInstBuilder(RISCV::BEQ)
785 .addReg(Reg: ScratchRegs[0])
786 .addReg(Reg: ScratchRegs[1])
787 .addExpr(Val: MCSymbolRefExpr::create(Symbol: Pass, Ctx&: OutContext)));
788
789 MCSymbol *Trap = OutContext.createTempSymbol();
790 OutStreamer->emitLabel(Symbol: Trap);
791 EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::EBREAK));
792 emitKCFITrapEntry(MF: *MI.getMF(), Symbol: Trap);
793 OutStreamer->emitLabel(Symbol: Pass);
794}
795
796void RISCVAsmPrinter::EmitHwasanMemaccessSymbols(Module &M) {
797 if (HwasanMemaccessSymbols.empty())
798 return;
799
800 assert(TM.getTargetTriple().isOSBinFormatELF());
801 // Use MCSubtargetInfo from TargetMachine. Individual functions may have
802 // attributes that differ from other functions in the module and we have no
803 // way to know which function is correct.
804 const MCSubtargetInfo &MCSTI = TM.getMCSubtargetInfo();
805
806 MCSymbol *HwasanTagMismatchV2Sym =
807 OutContext.getOrCreateSymbol(Name: "__hwasan_tag_mismatch_v2");
808 // Annotate symbol as one having incompatible calling convention, so
809 // run-time linkers can instead eagerly bind this function.
810 RISCVTargetStreamer &RTS = getTargetStreamer();
811 RTS.emitDirectiveVariantCC(Symbol&: *HwasanTagMismatchV2Sym);
812
813 const MCSymbolRefExpr *HwasanTagMismatchV2Ref =
814 MCSymbolRefExpr::create(Symbol: HwasanTagMismatchV2Sym, Ctx&: OutContext);
815 auto Expr = MCSpecifierExpr::create(Expr: HwasanTagMismatchV2Ref, S: RISCV::S_CALL_PLT,
816 Ctx&: OutContext);
817
818 for (auto &P : HwasanMemaccessSymbols) {
819 unsigned Reg = std::get<0>(t: P.first);
820 uint32_t AccessInfo = std::get<1>(t: P.first);
821 MCSymbol *Sym = P.second;
822
823 unsigned Size =
824 1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);
825 OutStreamer->switchSection(Section: OutContext.getELFSection(
826 Section: ".text.hot", Type: ELF::SHT_PROGBITS,
827 Flags: ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, EntrySize: 0, Group: Sym->getName(),
828 /*IsComdat=*/true));
829
830 OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_ELF_TypeFunction);
831 OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_Weak);
832 OutStreamer->emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_Hidden);
833 OutStreamer->emitLabel(Symbol: Sym);
834
835 // Extract shadow offset from ptr
836 EmitToStreamer(
837 S&: *OutStreamer,
838 Inst: MCInstBuilder(RISCV::SLLI).addReg(Reg: RISCV::X6).addReg(Reg).addImm(Val: 8),
839 SubtargetInfo: MCSTI);
840 EmitToStreamer(S&: *OutStreamer,
841 Inst: MCInstBuilder(RISCV::SRLI)
842 .addReg(Reg: RISCV::X6)
843 .addReg(Reg: RISCV::X6)
844 .addImm(Val: 12),
845 SubtargetInfo: MCSTI);
846 // load shadow tag in X6, X5 contains shadow base
847 EmitToStreamer(S&: *OutStreamer,
848 Inst: MCInstBuilder(RISCV::ADD)
849 .addReg(Reg: RISCV::X6)
850 .addReg(Reg: RISCV::X5)
851 .addReg(Reg: RISCV::X6),
852 SubtargetInfo: MCSTI);
853 EmitToStreamer(
854 S&: *OutStreamer,
855 Inst: MCInstBuilder(RISCV::LBU).addReg(Reg: RISCV::X6).addReg(Reg: RISCV::X6).addImm(Val: 0),
856 SubtargetInfo: MCSTI);
857 // Extract tag from pointer and compare it with loaded tag from shadow
858 EmitToStreamer(
859 S&: *OutStreamer,
860 Inst: MCInstBuilder(RISCV::SRLI).addReg(Reg: RISCV::X7).addReg(Reg).addImm(Val: 56),
861 SubtargetInfo: MCSTI);
862 MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
863 // X7 contains tag from the pointer, while X6 contains tag from memory
864 EmitToStreamer(S&: *OutStreamer,
865 Inst: MCInstBuilder(RISCV::BNE)
866 .addReg(Reg: RISCV::X7)
867 .addReg(Reg: RISCV::X6)
868 .addExpr(Val: MCSymbolRefExpr::create(
869 Symbol: HandleMismatchOrPartialSym, Ctx&: OutContext)),
870 SubtargetInfo: MCSTI);
871 MCSymbol *ReturnSym = OutContext.createTempSymbol();
872 OutStreamer->emitLabel(Symbol: ReturnSym);
873 EmitToStreamer(S&: *OutStreamer,
874 Inst: MCInstBuilder(RISCV::JALR)
875 .addReg(Reg: RISCV::X0)
876 .addReg(Reg: RISCV::X1)
877 .addImm(Val: 0),
878 SubtargetInfo: MCSTI);
879 OutStreamer->emitLabel(Symbol: HandleMismatchOrPartialSym);
880
881 EmitToStreamer(S&: *OutStreamer,
882 Inst: MCInstBuilder(RISCV::ADDI)
883 .addReg(Reg: RISCV::X28)
884 .addReg(Reg: RISCV::X0)
885 .addImm(Val: 16),
886 SubtargetInfo: MCSTI);
887 MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
888 EmitToStreamer(
889 S&: *OutStreamer,
890 Inst: MCInstBuilder(RISCV::BGEU)
891 .addReg(Reg: RISCV::X6)
892 .addReg(Reg: RISCV::X28)
893 .addExpr(Val: MCSymbolRefExpr::create(Symbol: HandleMismatchSym, Ctx&: OutContext)),
894 SubtargetInfo: MCSTI);
895
896 EmitToStreamer(
897 S&: *OutStreamer,
898 Inst: MCInstBuilder(RISCV::ANDI).addReg(Reg: RISCV::X28).addReg(Reg).addImm(Val: 0xF),
899 SubtargetInfo: MCSTI);
900
901 if (Size != 1)
902 EmitToStreamer(S&: *OutStreamer,
903 Inst: MCInstBuilder(RISCV::ADDI)
904 .addReg(Reg: RISCV::X28)
905 .addReg(Reg: RISCV::X28)
906 .addImm(Val: Size - 1),
907 SubtargetInfo: MCSTI);
908 EmitToStreamer(
909 S&: *OutStreamer,
910 Inst: MCInstBuilder(RISCV::BGE)
911 .addReg(Reg: RISCV::X28)
912 .addReg(Reg: RISCV::X6)
913 .addExpr(Val: MCSymbolRefExpr::create(Symbol: HandleMismatchSym, Ctx&: OutContext)),
914 SubtargetInfo: MCSTI);
915
916 EmitToStreamer(
917 S&: *OutStreamer,
918 Inst: MCInstBuilder(RISCV::ORI).addReg(Reg: RISCV::X6).addReg(Reg).addImm(Val: 0xF),
919 SubtargetInfo: MCSTI);
920 EmitToStreamer(
921 S&: *OutStreamer,
922 Inst: MCInstBuilder(RISCV::LBU).addReg(Reg: RISCV::X6).addReg(Reg: RISCV::X6).addImm(Val: 0),
923 SubtargetInfo: MCSTI);
924 EmitToStreamer(S&: *OutStreamer,
925 Inst: MCInstBuilder(RISCV::BEQ)
926 .addReg(Reg: RISCV::X6)
927 .addReg(Reg: RISCV::X7)
928 .addExpr(Val: MCSymbolRefExpr::create(Symbol: ReturnSym, Ctx&: OutContext)),
929 SubtargetInfo: MCSTI);
930
931 OutStreamer->emitLabel(Symbol: HandleMismatchSym);
932
933 // | Previous stack frames... |
934 // +=================================+ <-- [SP + 256]
935 // | ... |
936 // | |
937 // | Stack frame space for x12 - x31.|
938 // | |
939 // | ... |
940 // +---------------------------------+ <-- [SP + 96]
941 // | Saved x11(arg1), as |
942 // | __hwasan_check_* clobbers it. |
943 // +---------------------------------+ <-- [SP + 88]
944 // | Saved x10(arg0), as |
945 // | __hwasan_check_* clobbers it. |
946 // +---------------------------------+ <-- [SP + 80]
947 // | |
948 // | Stack frame space for x9. |
949 // +---------------------------------+ <-- [SP + 72]
950 // | |
951 // | Saved x8(fp), as |
952 // | __hwasan_check_* clobbers it. |
953 // +---------------------------------+ <-- [SP + 64]
954 // | ... |
955 // | |
956 // | Stack frame space for x2 - x7. |
957 // | |
958 // | ... |
959 // +---------------------------------+ <-- [SP + 16]
960 // | Return address (x1) for caller |
961 // | of __hwasan_check_*. |
962 // +---------------------------------+ <-- [SP + 8]
963 // | Reserved place for x0, possibly |
964 // | junk, since we don't save it. |
965 // +---------------------------------+ <-- [x2 / SP]
966
967 // Adjust sp
968 EmitToStreamer(S&: *OutStreamer,
969 Inst: MCInstBuilder(RISCV::ADDI)
970 .addReg(Reg: RISCV::X2)
971 .addReg(Reg: RISCV::X2)
972 .addImm(Val: -256),
973 SubtargetInfo: MCSTI);
974
975 // store x10(arg0) by new sp
976 EmitToStreamer(S&: *OutStreamer,
977 Inst: MCInstBuilder(RISCV::SD)
978 .addReg(Reg: RISCV::X10)
979 .addReg(Reg: RISCV::X2)
980 .addImm(Val: 8 * 10),
981 SubtargetInfo: MCSTI);
982 // store x11(arg1) by new sp
983 EmitToStreamer(S&: *OutStreamer,
984 Inst: MCInstBuilder(RISCV::SD)
985 .addReg(Reg: RISCV::X11)
986 .addReg(Reg: RISCV::X2)
987 .addImm(Val: 8 * 11),
988 SubtargetInfo: MCSTI);
989
990 // store x8(fp) by new sp
991 EmitToStreamer(
992 S&: *OutStreamer,
993 Inst: MCInstBuilder(RISCV::SD).addReg(Reg: RISCV::X8).addReg(Reg: RISCV::X2).addImm(Val: 8 *
994 8),
995 SubtargetInfo: MCSTI);
996 // store x1(ra) by new sp
997 EmitToStreamer(
998 S&: *OutStreamer,
999 Inst: MCInstBuilder(RISCV::SD).addReg(Reg: RISCV::X1).addReg(Reg: RISCV::X2).addImm(Val: 1 *
1000 8),
1001 SubtargetInfo: MCSTI);
1002 if (Reg != RISCV::X10)
1003 EmitToStreamer(
1004 S&: *OutStreamer,
1005 Inst: MCInstBuilder(RISCV::ADDI).addReg(Reg: RISCV::X10).addReg(Reg).addImm(Val: 0),
1006 SubtargetInfo: MCSTI);
1007 EmitToStreamer(S&: *OutStreamer,
1008 Inst: MCInstBuilder(RISCV::ADDI)
1009 .addReg(Reg: RISCV::X11)
1010 .addReg(Reg: RISCV::X0)
1011 .addImm(Val: AccessInfo & HWASanAccessInfo::RuntimeMask),
1012 SubtargetInfo: MCSTI);
1013
1014 EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(RISCV::PseudoCALL).addExpr(Val: Expr),
1015 SubtargetInfo: MCSTI);
1016 }
1017}
1018
1019void RISCVAsmPrinter::emitNoteGnuProperty(const Module &M) {
1020 assert(TM.getTargetTriple().isOSBinFormatELF() && "invalid binary format");
1021 uint32_t GnuProps = 0;
1022 if (const Metadata *const Flag = M.getModuleFlag(Key: "cf-protection-return");
1023 Flag && !mdconst::extract<ConstantInt>(MD: Flag)->isZero())
1024 GnuProps |= ELF::GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS;
1025
1026 if (const Metadata *const Flag = M.getModuleFlag(Key: "cf-protection-branch");
1027 Flag && !mdconst::extract<ConstantInt>(MD: Flag)->isZero()) {
1028 using namespace llvm::RISCVISAUtils;
1029 const Metadata *const CFBranchLabelSchemeFlag =
1030 M.getModuleFlag(Key: "cf-branch-label-scheme");
1031 assert(CFBranchLabelSchemeFlag &&
1032 "cf-protection=branch should come with cf-branch-label-scheme=... "
1033 "on RISC-V targets");
1034 const StringRef CFBranchLabelScheme =
1035 cast<MDString>(Val: CFBranchLabelSchemeFlag)->getString();
1036 switch (llvm::RISCVCFI::getZicfilpLabelScheme(CFBranchLabelScheme)) {
1037 case llvm::RISCVCFI::ZicfilpLabelSchemeKind::Invalid:
1038 reportFatalInternalError(reason: "invalid RISC-V Zicfilp label scheme");
1039 case llvm::RISCVCFI::ZicfilpLabelSchemeKind::Unlabeled:
1040 GnuProps |= ELF::GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED;
1041 break;
1042 case llvm::RISCVCFI::ZicfilpLabelSchemeKind::FuncSig:
1043 // TODO: Emit the func-sig bit after the feature is implemented
1044 reportFatalUsageError(reason: "the complete func-sig label scheme feature is not "
1045 "implemented yet");
1046 break;
1047 }
1048 }
1049
1050 if (!GnuProps)
1051 return;
1052
1053 auto &RTS = static_cast<RISCVTargetELFStreamer &>(getTargetStreamer());
1054 RTS.emitNoteGnuPropertySection(Feature1And: GnuProps);
1055}
1056
1057static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
1058 const AsmPrinter &AP) {
1059 MCContext &Ctx = AP.OutContext;
1060 RISCV::Specifier Kind;
1061
1062 switch (MO.getTargetFlags()) {
1063 default:
1064 llvm_unreachable("Unknown target flag on GV operand");
1065 case RISCVII::MO_None:
1066 Kind = RISCV::S_None;
1067 break;
1068 case RISCVII::MO_CALL:
1069 Kind = RISCV::S_CALL_PLT;
1070 break;
1071 case RISCVII::MO_LO:
1072 Kind = RISCV::S_LO;
1073 break;
1074 case RISCVII::MO_HI:
1075 Kind = ELF::R_RISCV_HI20;
1076 break;
1077 case RISCVII::MO_PCREL_LO:
1078 Kind = RISCV::S_PCREL_LO;
1079 break;
1080 case RISCVII::MO_PCREL_HI:
1081 Kind = RISCV::S_PCREL_HI;
1082 break;
1083 case RISCVII::MO_GOT_HI:
1084 Kind = RISCV::S_GOT_HI;
1085 break;
1086 case RISCVII::MO_TPREL_LO:
1087 Kind = RISCV::S_TPREL_LO;
1088 break;
1089 case RISCVII::MO_TPREL_HI:
1090 Kind = ELF::R_RISCV_TPREL_HI20;
1091 break;
1092 case RISCVII::MO_TPREL_ADD:
1093 Kind = ELF::R_RISCV_TPREL_ADD;
1094 break;
1095 case RISCVII::MO_TLS_GOT_HI:
1096 Kind = ELF::R_RISCV_TLS_GOT_HI20;
1097 break;
1098 case RISCVII::MO_TLS_GD_HI:
1099 Kind = ELF::R_RISCV_TLS_GD_HI20;
1100 break;
1101 case RISCVII::MO_TLSDESC_HI:
1102 Kind = ELF::R_RISCV_TLSDESC_HI20;
1103 break;
1104 case RISCVII::MO_TLSDESC_LOAD_LO:
1105 Kind = ELF::R_RISCV_TLSDESC_LOAD_LO12;
1106 break;
1107 case RISCVII::MO_TLSDESC_ADD_LO:
1108 Kind = ELF::R_RISCV_TLSDESC_ADD_LO12;
1109 break;
1110 case RISCVII::MO_TLSDESC_CALL:
1111 Kind = ELF::R_RISCV_TLSDESC_CALL;
1112 break;
1113 case RISCVII::MO_QC_ACCESS:
1114 Kind = RISCV::S_QC_ACCESS;
1115 break;
1116 }
1117
1118 const MCExpr *ME = MCSymbolRefExpr::create(Symbol: Sym, Ctx);
1119
1120 if (!MO.isJTI() && !MO.isMBB() && MO.getOffset())
1121 ME = MCBinaryExpr::createAdd(
1122 LHS: ME, RHS: MCConstantExpr::create(Value: MO.getOffset(), Ctx), Ctx);
1123
1124 if (Kind != RISCV::S_None)
1125 ME = MCSpecifierExpr::create(Expr: ME, S: Kind, Ctx);
1126 return MCOperand::createExpr(Val: ME);
1127}
1128
1129bool RISCVAsmPrinter::lowerOperand(const MachineOperand &MO,
1130 MCOperand &MCOp) const {
1131 switch (MO.getType()) {
1132 default:
1133 report_fatal_error(reason: "lowerOperand: unknown operand type");
1134 case MachineOperand::MO_Register:
1135 // Ignore all implicit register operands.
1136 if (MO.isImplicit())
1137 return false;
1138 MCOp = MCOperand::createReg(Reg: MO.getReg());
1139 break;
1140 case MachineOperand::MO_RegisterMask:
1141 // Regmasks are like implicit defs.
1142 return false;
1143 case MachineOperand::MO_Immediate:
1144 MCOp = MCOperand::createImm(Val: MO.getImm());
1145 break;
1146 case MachineOperand::MO_MachineBasicBlock:
1147 MCOp = lowerSymbolOperand(MO, Sym: MO.getMBB()->getSymbol(), AP: *this);
1148 break;
1149 case MachineOperand::MO_GlobalAddress:
1150 MCOp = lowerSymbolOperand(MO, Sym: getSymbolPreferLocal(GV: *MO.getGlobal()), AP: *this);
1151 break;
1152 case MachineOperand::MO_BlockAddress:
1153 MCOp = lowerSymbolOperand(MO, Sym: GetBlockAddressSymbol(BA: MO.getBlockAddress()),
1154 AP: *this);
1155 break;
1156 case MachineOperand::MO_ExternalSymbol:
1157 MCOp = lowerSymbolOperand(MO, Sym: GetExternalSymbolSymbol(Sym: MO.getSymbolName()),
1158 AP: *this);
1159 break;
1160 case MachineOperand::MO_ConstantPoolIndex:
1161 MCOp = lowerSymbolOperand(MO, Sym: GetCPISymbol(CPID: MO.getIndex()), AP: *this);
1162 break;
1163 case MachineOperand::MO_JumpTableIndex:
1164 MCOp = lowerSymbolOperand(MO, Sym: GetJTISymbol(JTID: MO.getIndex()), AP: *this);
1165 break;
1166 case MachineOperand::MO_MCSymbol:
1167 MCOp = lowerSymbolOperand(MO, Sym: MO.getMCSymbol(), AP: *this);
1168 break;
1169 }
1170 return true;
1171}
1172
1173static bool lowerRISCVVMachineInstrToMCInst(const MachineInstr *MI,
1174 MCInst &OutMI,
1175 const RISCVSubtarget *STI) {
1176 const RISCVVPseudosTable::PseudoInfo *RVV =
1177 RISCVVPseudosTable::getPseudoInfo(Pseudo: MI->getOpcode());
1178 if (!RVV)
1179 return false;
1180
1181 OutMI.setOpcode(RVV->BaseInstr);
1182
1183 const TargetInstrInfo *TII = STI->getInstrInfo();
1184 const TargetRegisterInfo *TRI = STI->getRegisterInfo();
1185 assert(TRI && "TargetRegisterInfo expected");
1186
1187 const MCInstrDesc &MCID = MI->getDesc();
1188 uint64_t TSFlags = MCID.TSFlags;
1189 unsigned NumOps = MI->getNumExplicitOperands();
1190
1191 // Skip policy, SEW, VL, VXRM/FRM operands which are the last operands if
1192 // present.
1193 if (RISCVII::hasVecPolicyOp(TSFlags))
1194 --NumOps;
1195 if (RISCVII::hasSEWOp(TSFlags))
1196 --NumOps;
1197 if (RISCVII::hasVLOp(TSFlags))
1198 --NumOps;
1199 if (RISCVII::hasRoundModeOp(TSFlags))
1200 --NumOps;
1201 if (RISCVII::hasTWidenOp(TSFlags))
1202 --NumOps;
1203 if (RISCVII::hasTMOp(TSFlags))
1204 --NumOps;
1205 if (RISCVII::hasTKOp(TSFlags))
1206 --NumOps;
1207
1208 bool hasVLOutput = RISCVInstrInfo::isFaultOnlyFirstLoad(MI: *MI);
1209 for (unsigned OpNo = 0; OpNo != NumOps; ++OpNo) {
1210 const MachineOperand &MO = MI->getOperand(i: OpNo);
1211 // Skip vl output. It should be the second output.
1212 if (hasVLOutput && OpNo == 1)
1213 continue;
1214
1215 // Skip passthru op. It should be the first operand after the defs.
1216 if (OpNo == MI->getNumExplicitDefs() && MO.isReg() && MO.isTied()) {
1217 assert(MCID.getOperandConstraint(OpNo, MCOI::TIED_TO) == 0 &&
1218 "Expected tied to first def.");
1219 const MCInstrDesc &OutMCID = TII->get(Opcode: OutMI.getOpcode());
1220 // Skip if the next operand in OutMI is not supposed to be tied. Unless it
1221 // is a _TIED instruction.
1222 if (OutMCID.getOperandConstraint(OpNum: OutMI.getNumOperands(), Constraint: MCOI::TIED_TO) <
1223 0 &&
1224 !RISCVII::isTiedPseudo(TSFlags))
1225 continue;
1226 }
1227
1228 MCOperand MCOp;
1229 switch (MO.getType()) {
1230 default:
1231 llvm_unreachable("Unknown operand type");
1232 case MachineOperand::MO_Register: {
1233 Register Reg = MO.getReg();
1234
1235 if (RISCV::VRM2RegClass.contains(Reg) ||
1236 RISCV::VRM4RegClass.contains(Reg) ||
1237 RISCV::VRM8RegClass.contains(Reg)) {
1238 Reg = TRI->getSubReg(Reg, Idx: RISCV::sub_vrm1_0);
1239 assert(Reg && "Subregister does not exist");
1240 } else if (RISCV::FPR16RegClass.contains(Reg)) {
1241 Reg =
1242 TRI->getMatchingSuperReg(Reg, SubIdx: RISCV::sub_16, RC: &RISCV::FPR32RegClass);
1243 assert(Reg && "Subregister does not exist");
1244 } else if (RISCV::FPR64RegClass.contains(Reg)) {
1245 Reg = TRI->getSubReg(Reg, Idx: RISCV::sub_32);
1246 assert(Reg && "Superregister does not exist");
1247 } else if (RISCV::VRN2M1RegClass.contains(Reg) ||
1248 RISCV::VRN2M2RegClass.contains(Reg) ||
1249 RISCV::VRN2M4RegClass.contains(Reg) ||
1250 RISCV::VRN3M1RegClass.contains(Reg) ||
1251 RISCV::VRN3M2RegClass.contains(Reg) ||
1252 RISCV::VRN4M1RegClass.contains(Reg) ||
1253 RISCV::VRN4M2RegClass.contains(Reg) ||
1254 RISCV::VRN5M1RegClass.contains(Reg) ||
1255 RISCV::VRN6M1RegClass.contains(Reg) ||
1256 RISCV::VRN7M1RegClass.contains(Reg) ||
1257 RISCV::VRN8M1RegClass.contains(Reg)) {
1258 Reg = TRI->getSubReg(Reg, Idx: RISCV::sub_vrm1_0);
1259 assert(Reg && "Subregister does not exist");
1260 }
1261
1262 MCOp = MCOperand::createReg(Reg);
1263 break;
1264 }
1265 case MachineOperand::MO_Immediate:
1266 MCOp = MCOperand::createImm(Val: MO.getImm());
1267 break;
1268 }
1269 OutMI.addOperand(Op: MCOp);
1270 }
1271
1272 // Unmasked pseudo instructions need to append dummy mask operand to
1273 // V instructions. All V instructions are modeled as the masked version.
1274 const MCInstrDesc &OutMCID = TII->get(Opcode: OutMI.getOpcode());
1275 if (OutMI.getNumOperands() < OutMCID.getNumOperands()) {
1276 assert(OutMCID.operands()[OutMI.getNumOperands()].OperandType ==
1277 RISCVOp::OPERAND_VMASK &&
1278 "Expected only mask operand to be missing");
1279 OutMI.addOperand(Op: MCOperand::createReg(Reg: RISCV::NoRegister));
1280 }
1281
1282 assert(OutMI.getNumOperands() == OutMCID.getNumOperands());
1283 return true;
1284}
1285
1286void RISCVAsmPrinter::lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) {
1287 if (lowerRISCVVMachineInstrToMCInst(MI, OutMI, STI))
1288 return;
1289
1290 OutMI.setOpcode(MI->getOpcode());
1291
1292 for (const MachineOperand &MO : MI->operands()) {
1293 MCOperand MCOp;
1294 if (lowerOperand(MO, MCOp))
1295 OutMI.addOperand(Op: MCOp);
1296 }
1297}
1298
1299void RISCVAsmPrinter::emitMachineConstantPoolValue(
1300 MachineConstantPoolValue *MCPV) {
1301 auto *RCPV = static_cast<RISCVConstantPoolValue *>(MCPV);
1302 MCSymbol *MCSym;
1303
1304 if (RCPV->isGlobalValue()) {
1305 auto *GV = RCPV->getGlobalValue();
1306 MCSym = getSymbol(GV);
1307 } else {
1308 assert(RCPV->isExtSymbol() && "unrecognized constant pool type");
1309 auto Sym = RCPV->getSymbol();
1310 MCSym = GetExternalSymbolSymbol(Sym);
1311 }
1312
1313 const MCExpr *Expr = MCSymbolRefExpr::create(Symbol: MCSym, Ctx&: OutContext);
1314 uint64_t Size = getDataLayout().getTypeAllocSize(Ty: RCPV->getType());
1315 OutStreamer->emitValue(Value: Expr, Size);
1316}
1317
1318char RISCVAsmPrinter::ID = 0;
1319
1320INITIALIZE_PASS(RISCVAsmPrinter, "riscv-asm-printer", "RISC-V Assembly Printer",
1321 false, false)
1322