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