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